mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to s-c.
This commit is contained in:
commit
fb25194f74
@ -52,10 +52,10 @@ TEST_FILES = \
|
|||||||
exceptions_in_success_events_iframe.html \
|
exceptions_in_success_events_iframe.html \
|
||||||
helpers.js \
|
helpers.js \
|
||||||
leaving_page_iframe.html \
|
leaving_page_iframe.html \
|
||||||
|
test_add_put.html \
|
||||||
test_add_twice_failure.html \
|
test_add_twice_failure.html \
|
||||||
test_advance.html \
|
test_advance.html \
|
||||||
test_autoIncrement_indexes.html \
|
test_autoIncrement_indexes.html \
|
||||||
test_bad_keypath.html \
|
|
||||||
test_bfcache.html \
|
test_bfcache.html \
|
||||||
test_clear.html \
|
test_clear.html \
|
||||||
test_cmp.html \
|
test_cmp.html \
|
||||||
|
180
dom/indexedDB/test/test_add_put.html
Normal file
180
dom/indexedDB/test/test_add_put.html
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
<!--
|
||||||
|
Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
-->
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Indexed Database Property Test</title>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||||
|
|
||||||
|
<script type="text/javascript;version=1.7">
|
||||||
|
function testSteps()
|
||||||
|
{
|
||||||
|
const name = window.location.pathname;
|
||||||
|
let openRequest = mozIndexedDB.open(name, 1);
|
||||||
|
openRequest.onerror = errorHandler;
|
||||||
|
openRequest.onupgradeneeded = grabEventAndContinueHandler;
|
||||||
|
openRequest.onsuccess = unexpectedSuccessHandler;
|
||||||
|
let event = yield;
|
||||||
|
let db = event.target.result;
|
||||||
|
let trans = event.target.transaction;
|
||||||
|
|
||||||
|
for each (let autoincrement in [true, false]) {
|
||||||
|
for each (let keypath in [false, true, "missing", "invalid"]) {
|
||||||
|
for each (let method in ["put", "add"]) {
|
||||||
|
for each (let explicit in [true, false, undefined, "invalid"]) {
|
||||||
|
for each (let existing in [true, false]) {
|
||||||
|
let speccedNoKey = (keypath == false || keypath == "missing") &&
|
||||||
|
!explicit;
|
||||||
|
|
||||||
|
// We can't do 'existing' checks if we use autogenerated key
|
||||||
|
if (speccedNoKey && autoincrement && existing) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create store
|
||||||
|
if (db.objectStoreNames.contains("mystore"))
|
||||||
|
db.deleteObjectStore("mystore");
|
||||||
|
let store = db.createObjectStore("mystore",
|
||||||
|
{ autoIncrement: autoincrement,
|
||||||
|
keyPath: (keypath ? "id" : null) });
|
||||||
|
|
||||||
|
test = " for test " + JSON.stringify({ autoincrement: autoincrement,
|
||||||
|
keypath: keypath,
|
||||||
|
method: method,
|
||||||
|
explicit: explicit === undefined ? "undefined" : explicit,
|
||||||
|
existing: existing });
|
||||||
|
|
||||||
|
// Insert "existing" data if needed
|
||||||
|
if (existing) {
|
||||||
|
if (keypath)
|
||||||
|
store.add({ existing: "data", id: 5 }).onsuccess = grabEventAndContinueHandler;
|
||||||
|
else
|
||||||
|
store.add({ existing: "data" }, 5).onsuccess = grabEventAndContinueHandler;
|
||||||
|
|
||||||
|
let e = yield;
|
||||||
|
is(e.type, "success", "success inserting existing" + test);
|
||||||
|
is(e.target.result, 5, "inserted correct key" + test);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up value to be inserted
|
||||||
|
let value = { theObj: true };
|
||||||
|
if (keypath === true) {
|
||||||
|
value.id = 5;
|
||||||
|
}
|
||||||
|
else if (keypath === "invalid") {
|
||||||
|
value.id = /x/;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Which arguments are passed to function
|
||||||
|
args = [value];
|
||||||
|
if (explicit === true) {
|
||||||
|
args.push(5);
|
||||||
|
}
|
||||||
|
else if (explicit === undefined) {
|
||||||
|
args.push(undefined);
|
||||||
|
}
|
||||||
|
else if (explicit === "invalid") {
|
||||||
|
args.push(/x/);
|
||||||
|
}
|
||||||
|
|
||||||
|
let expected = expectedResult(method, keypath, explicit, autoincrement, existing);
|
||||||
|
|
||||||
|
ok(true, "making call" + test);
|
||||||
|
|
||||||
|
// Make function call for throwing functions
|
||||||
|
if (expected === "throw") {
|
||||||
|
try {
|
||||||
|
store[method].apply(store, args);
|
||||||
|
ok(false, "should have thrown" + test);
|
||||||
|
}
|
||||||
|
catch (ex) {
|
||||||
|
ok(true, "did throw" + test);
|
||||||
|
ok(ex instanceof IDBDatabaseException, "Got a IDBDatabaseException" + test);
|
||||||
|
is(ex.code, IDBDatabaseException.DATA_ERR, "expect a DATA_ERR" + test);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make non-throwing function call
|
||||||
|
let req = store[method].apply(store, args);
|
||||||
|
req.onsuccess = req.onerror = grabEventAndContinueHandler
|
||||||
|
let e = yield;
|
||||||
|
|
||||||
|
// Figure out what key we used
|
||||||
|
let key = 5;
|
||||||
|
if (autoincrement && speccedNoKey) {
|
||||||
|
key = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjust value if expected
|
||||||
|
if (autoincrement && keypath && speccedNoKey) {
|
||||||
|
value.id = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check result
|
||||||
|
if (expected === "error") {
|
||||||
|
is(e.type, "error", "write should fail" + test);
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
is(e.type, "success", "write should succeed" + test);
|
||||||
|
if (autoincrement && speccedNoKey) {
|
||||||
|
todo_is(e.target.result, key, "(fix ai) write should return correct key" + test);
|
||||||
|
key = e.target.result;
|
||||||
|
if (keypath) {
|
||||||
|
value.id = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
is(e.target.result, key, "write should return correct key" + test);
|
||||||
|
}
|
||||||
|
|
||||||
|
store.get(key).onsuccess = grabEventAndContinueHandler;
|
||||||
|
e = yield;
|
||||||
|
is(e.type, "success", "read back should succeed" + test);
|
||||||
|
is(JSON.stringify(e.target.result),
|
||||||
|
JSON.stringify(value),
|
||||||
|
"read back should return correct value" + test);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function expectedResult(method, keypath, explicit, autoincrement, existing) {
|
||||||
|
if (keypath && explicit)
|
||||||
|
return "throw";
|
||||||
|
if (!keypath && !explicit && !autoincrement)
|
||||||
|
return "throw";
|
||||||
|
if (keypath == "invalid")
|
||||||
|
return "throw";
|
||||||
|
if (keypath == "missing" && !autoincrement)
|
||||||
|
return "throw";
|
||||||
|
if (explicit == "invalid")
|
||||||
|
return "throw";
|
||||||
|
|
||||||
|
if (method == "add" && existing)
|
||||||
|
return "error";
|
||||||
|
|
||||||
|
return "success";
|
||||||
|
}
|
||||||
|
|
||||||
|
openRequest.onsuccess = grabEventAndContinueHandler;
|
||||||
|
yield;
|
||||||
|
|
||||||
|
finishTest();
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body onload="runTest();"></body>
|
||||||
|
|
||||||
|
</html>
|
@ -1,49 +0,0 @@
|
|||||||
<!--
|
|
||||||
Any copyright is dedicated to the Public Domain.
|
|
||||||
http://creativecommons.org/publicdomain/zero/1.0/
|
|
||||||
-->
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Indexed Database Property Test</title>
|
|
||||||
|
|
||||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
|
||||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
|
||||||
|
|
||||||
<script type="text/javascript;version=1.7">
|
|
||||||
function testSteps()
|
|
||||||
{
|
|
||||||
const name = window.location.pathname;
|
|
||||||
const description = "My Test Database";
|
|
||||||
|
|
||||||
let request = mozIndexedDB.open(name, 1, description);
|
|
||||||
request.onerror = errorHandler;
|
|
||||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
|
||||||
let event = yield;
|
|
||||||
|
|
||||||
let db = request.result;
|
|
||||||
|
|
||||||
let objectStore = db.createObjectStore("foo", { keyPath: "keyPath" });
|
|
||||||
|
|
||||||
request = objectStore.add({keyPath:"foo"});
|
|
||||||
request.onerror = errorHandler;
|
|
||||||
request.onsuccess = grabEventAndContinueHandler;
|
|
||||||
event = yield;
|
|
||||||
|
|
||||||
try {
|
|
||||||
request = objectStore.add({});
|
|
||||||
ok(false, "Shouldn't get here!");
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
is(e.code, IDBDatabaseException.DATA_ERR, "Good error");
|
|
||||||
}
|
|
||||||
|
|
||||||
finishTest();
|
|
||||||
yield;
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body onload="runTest();"></body>
|
|
||||||
|
|
||||||
</html>
|
|
@ -93,6 +93,13 @@ public class BrowserContract {
|
|||||||
public static final class Bookmarks implements CommonColumns, URLColumns, ImageColumns, SyncColumns {
|
public static final class Bookmarks implements CommonColumns, URLColumns, ImageColumns, SyncColumns {
|
||||||
private Bookmarks() {}
|
private Bookmarks() {}
|
||||||
|
|
||||||
|
public static final String MOBILE_FOLDER_GUID = "mobile";
|
||||||
|
public static final String PLACES_FOLDER_GUID = "places";
|
||||||
|
public static final String MENU_FOLDER_GUID = "menu";
|
||||||
|
public static final String TAGS_FOLDER_GUID = "tags";
|
||||||
|
public static final String TOOLBAR_FOLDER_GUID = "toolbar";
|
||||||
|
public static final String UNFILED_FOLDER_GUID = "unfiled";
|
||||||
|
|
||||||
public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "bookmarks");
|
public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "bookmarks");
|
||||||
|
|
||||||
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/bookmark";
|
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/bookmark";
|
||||||
|
@ -83,6 +83,9 @@ public class BrowserProvider extends ContentProvider {
|
|||||||
static final String TABLE_HISTORY = "history";
|
static final String TABLE_HISTORY = "history";
|
||||||
static final String TABLE_IMAGES = "images";
|
static final String TABLE_IMAGES = "images";
|
||||||
|
|
||||||
|
static final String VIEW_BOOKMARKS_WITH_IMAGES = "bookmarks_with_images";
|
||||||
|
static final String VIEW_HISTORY_WITH_IMAGES = "history_with_images";
|
||||||
|
|
||||||
// Bookmark matches
|
// Bookmark matches
|
||||||
static final int BOOKMARKS = 100;
|
static final int BOOKMARKS = 100;
|
||||||
static final int BOOKMARKS_ID = 101;
|
static final int BOOKMARKS_ID = 101;
|
||||||
@ -106,12 +109,20 @@ public class BrowserProvider extends ContentProvider {
|
|||||||
static final String DEFAULT_HISTORY_SORT_ORDER = History.DATE_LAST_VISITED + " DESC";
|
static final String DEFAULT_HISTORY_SORT_ORDER = History.DATE_LAST_VISITED + " DESC";
|
||||||
|
|
||||||
static final String TABLE_BOOKMARKS_JOIN_IMAGES = TABLE_BOOKMARKS + " LEFT OUTER JOIN " +
|
static final String TABLE_BOOKMARKS_JOIN_IMAGES = TABLE_BOOKMARKS + " LEFT OUTER JOIN " +
|
||||||
TABLE_IMAGES + " ON " + qualifyColumnValue(TABLE_BOOKMARKS, Bookmarks.URL) +
|
"(SELECT " + Images.URL + ", " + Images.FAVICON + ", " + Images.THUMBNAIL + " FROM " +
|
||||||
" = " + qualifyColumnValue(TABLE_IMAGES, Images.URL);
|
TABLE_IMAGES + ", " + TABLE_BOOKMARKS + " WHERE " +
|
||||||
|
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " = " +
|
||||||
|
qualifyColumn(TABLE_IMAGES, Images.URL) + ") AS bookmark_images ON " +
|
||||||
|
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " = " +
|
||||||
|
qualifyColumn("bookmark_images", Images.URL);
|
||||||
|
|
||||||
static final String TABLE_HISTORY_JOIN_IMAGES = TABLE_HISTORY + " LEFT OUTER JOIN " +
|
static final String TABLE_HISTORY_JOIN_IMAGES = TABLE_HISTORY + " LEFT OUTER JOIN " +
|
||||||
TABLE_IMAGES + " ON " + qualifyColumnValue(TABLE_HISTORY, History.URL) +
|
"(SELECT " + Images.URL + ", " + Images.FAVICON + ", " + Images.THUMBNAIL + " FROM " +
|
||||||
" = " + qualifyColumnValue(TABLE_IMAGES, Images.URL);
|
TABLE_IMAGES + ", " + TABLE_HISTORY + " WHERE " +
|
||||||
|
qualifyColumn(TABLE_HISTORY, History.URL) + " = " +
|
||||||
|
qualifyColumn(TABLE_IMAGES, Images.URL) + ") AS history_images ON " +
|
||||||
|
qualifyColumn(TABLE_HISTORY, History.URL) + " = " +
|
||||||
|
qualifyColumn("history_images", Images.URL);
|
||||||
|
|
||||||
static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
|
static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
|
||||||
|
|
||||||
@ -131,7 +142,7 @@ public class BrowserProvider extends ContentProvider {
|
|||||||
URI_MATCHER.addURI(BrowserContract.AUTHORITY, "bookmarks/folder/#", BOOKMARKS_FOLDER_ID);
|
URI_MATCHER.addURI(BrowserContract.AUTHORITY, "bookmarks/folder/#", BOOKMARKS_FOLDER_ID);
|
||||||
|
|
||||||
map = BOOKMARKS_PROJECTION_MAP;
|
map = BOOKMARKS_PROJECTION_MAP;
|
||||||
map.put(Bookmarks._ID, qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID));
|
map.put(Bookmarks._ID, Bookmarks._ID);
|
||||||
map.put(Bookmarks.TITLE, Bookmarks.TITLE);
|
map.put(Bookmarks.TITLE, Bookmarks.TITLE);
|
||||||
map.put(Bookmarks.URL, Bookmarks.URL);
|
map.put(Bookmarks.URL, Bookmarks.URL);
|
||||||
map.put(Bookmarks.FAVICON, Bookmarks.FAVICON);
|
map.put(Bookmarks.FAVICON, Bookmarks.FAVICON);
|
||||||
@ -142,41 +153,41 @@ public class BrowserProvider extends ContentProvider {
|
|||||||
map.put(Bookmarks.TAGS, Bookmarks.TAGS);
|
map.put(Bookmarks.TAGS, Bookmarks.TAGS);
|
||||||
map.put(Bookmarks.DESCRIPTION, Bookmarks.DESCRIPTION);
|
map.put(Bookmarks.DESCRIPTION, Bookmarks.DESCRIPTION);
|
||||||
map.put(Bookmarks.KEYWORD, Bookmarks.KEYWORD);
|
map.put(Bookmarks.KEYWORD, Bookmarks.KEYWORD);
|
||||||
map.put(Bookmarks.DATE_CREATED, qualifyColumn(TABLE_BOOKMARKS, Bookmarks.DATE_CREATED));
|
map.put(Bookmarks.DATE_CREATED, Bookmarks.DATE_CREATED);
|
||||||
map.put(Bookmarks.DATE_MODIFIED, qualifyColumn(TABLE_BOOKMARKS, Bookmarks.DATE_MODIFIED));
|
map.put(Bookmarks.DATE_MODIFIED, Bookmarks.DATE_MODIFIED);
|
||||||
map.put(Bookmarks.GUID, qualifyColumn(TABLE_BOOKMARKS, Bookmarks.GUID));
|
map.put(Bookmarks.GUID, Bookmarks.GUID);
|
||||||
map.put(Bookmarks.IS_DELETED, qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED));
|
map.put(Bookmarks.IS_DELETED, Bookmarks.IS_DELETED);
|
||||||
|
|
||||||
// History
|
// History
|
||||||
URI_MATCHER.addURI(BrowserContract.AUTHORITY, "history", HISTORY);
|
URI_MATCHER.addURI(BrowserContract.AUTHORITY, "history", HISTORY);
|
||||||
URI_MATCHER.addURI(BrowserContract.AUTHORITY, "history/#", HISTORY_ID);
|
URI_MATCHER.addURI(BrowserContract.AUTHORITY, "history/#", HISTORY_ID);
|
||||||
|
|
||||||
map = HISTORY_PROJECTION_MAP;
|
map = HISTORY_PROJECTION_MAP;
|
||||||
map.put(History._ID, qualifyColumn(TABLE_HISTORY, History._ID));
|
map.put(History._ID, History._ID);
|
||||||
map.put(History.TITLE, History.TITLE);
|
map.put(History.TITLE, History.TITLE);
|
||||||
map.put(History.URL, History.URL);
|
map.put(History.URL, History.URL);
|
||||||
map.put(History.FAVICON, History.FAVICON);
|
map.put(History.FAVICON, History.FAVICON);
|
||||||
map.put(History.THUMBNAIL, History.THUMBNAIL);
|
map.put(History.THUMBNAIL, History.THUMBNAIL);
|
||||||
map.put(History.VISITS, History.VISITS);
|
map.put(History.VISITS, History.VISITS);
|
||||||
map.put(History.DATE_LAST_VISITED, History.DATE_LAST_VISITED);
|
map.put(History.DATE_LAST_VISITED, History.DATE_LAST_VISITED);
|
||||||
map.put(History.DATE_CREATED, qualifyColumn(TABLE_HISTORY, History.DATE_CREATED));
|
map.put(History.DATE_CREATED, History.DATE_CREATED);
|
||||||
map.put(History.DATE_MODIFIED, qualifyColumn(TABLE_HISTORY, History.DATE_MODIFIED));
|
map.put(History.DATE_MODIFIED, History.DATE_MODIFIED);
|
||||||
map.put(History.GUID, qualifyColumn(TABLE_HISTORY, History.GUID));
|
map.put(History.GUID, History.GUID);
|
||||||
map.put(History.IS_DELETED, qualifyColumn(TABLE_HISTORY, History.IS_DELETED));
|
map.put(History.IS_DELETED, History.IS_DELETED);
|
||||||
|
|
||||||
// Images
|
// Images
|
||||||
URI_MATCHER.addURI(BrowserContract.AUTHORITY, "images", IMAGES);
|
URI_MATCHER.addURI(BrowserContract.AUTHORITY, "images", IMAGES);
|
||||||
|
|
||||||
map = IMAGES_PROJECTION_MAP;
|
map = IMAGES_PROJECTION_MAP;
|
||||||
map.put(Images._ID, qualifyColumn(TABLE_IMAGES, Images._ID));
|
map.put(Images._ID, Images._ID);
|
||||||
map.put(Images.URL, Images.URL);
|
map.put(Images.URL, Images.URL);
|
||||||
map.put(Images.FAVICON, Images.FAVICON);
|
map.put(Images.FAVICON, Images.FAVICON);
|
||||||
map.put(Images.FAVICON_URL, Images.FAVICON_URL);
|
map.put(Images.FAVICON_URL, Images.FAVICON_URL);
|
||||||
map.put(Images.THUMBNAIL, Images.THUMBNAIL);
|
map.put(Images.THUMBNAIL, Images.THUMBNAIL);
|
||||||
map.put(Images.DATE_CREATED, qualifyColumn(TABLE_IMAGES, Images.DATE_CREATED));
|
map.put(Images.DATE_CREATED, Images.DATE_CREATED);
|
||||||
map.put(Images.DATE_MODIFIED, qualifyColumn(TABLE_IMAGES, Images.DATE_MODIFIED));
|
map.put(Images.DATE_MODIFIED, Images.DATE_MODIFIED);
|
||||||
map.put(Images.GUID, qualifyColumn(TABLE_IMAGES, Images.GUID));
|
map.put(Images.GUID, Images.GUID);
|
||||||
map.put(Images.IS_DELETED, qualifyColumn(TABLE_IMAGES, Images.IS_DELETED));
|
map.put(Images.IS_DELETED, Images.IS_DELETED);
|
||||||
|
|
||||||
// Schema
|
// Schema
|
||||||
URI_MATCHER.addURI(BrowserContract.AUTHORITY, "schema", SCHEMA);
|
URI_MATCHER.addURI(BrowserContract.AUTHORITY, "schema", SCHEMA);
|
||||||
@ -186,10 +197,6 @@ public class BrowserProvider extends ContentProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static final String qualifyColumn(String table, String column) {
|
static final String qualifyColumn(String table, String column) {
|
||||||
return table + "." + column + " AS " + column;
|
|
||||||
}
|
|
||||||
|
|
||||||
static final String qualifyColumnValue(String table, String column) {
|
|
||||||
return table + "." + column;
|
return table + "." + column;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,6 +246,16 @@ public class BrowserProvider extends ContentProvider {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean hasImagesInProjection(String[] projection) {
|
||||||
|
for (int i = 0; i < projection.length; ++i) {
|
||||||
|
if (projection[i].equals(Images.FAVICON) ||
|
||||||
|
projection[i].equals(Images.THUMBNAIL))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
final class DatabaseHelper extends SQLiteOpenHelper {
|
final class DatabaseHelper extends SQLiteOpenHelper {
|
||||||
public DatabaseHelper(Context context, String databasePath) {
|
public DatabaseHelper(Context context, String databasePath) {
|
||||||
super(context, databasePath, null, DATABASE_VERSION);
|
super(context, databasePath, null, DATABASE_VERSION);
|
||||||
@ -314,9 +331,34 @@ public class BrowserProvider extends ContentProvider {
|
|||||||
db.execSQL("CREATE INDEX images_modified_index ON " + TABLE_IMAGES + "("
|
db.execSQL("CREATE INDEX images_modified_index ON " + TABLE_IMAGES + "("
|
||||||
+ Images.DATE_MODIFIED + ")");
|
+ Images.DATE_MODIFIED + ")");
|
||||||
|
|
||||||
|
db.execSQL("CREATE VIEW IF NOT EXISTS " + VIEW_BOOKMARKS_WITH_IMAGES + " AS " +
|
||||||
|
"SELECT " + qualifyColumn(TABLE_BOOKMARKS, "*") +
|
||||||
|
", " + Images.FAVICON + ", " + Images.THUMBNAIL + " FROM " +
|
||||||
|
TABLE_BOOKMARKS_JOIN_IMAGES);
|
||||||
|
|
||||||
|
db.execSQL("CREATE VIEW IF NOT EXISTS " + VIEW_HISTORY_WITH_IMAGES + " AS " +
|
||||||
|
"SELECT " + qualifyColumn(TABLE_HISTORY, "*") +
|
||||||
|
", " + Images.FAVICON + ", " + Images.THUMBNAIL + " FROM " +
|
||||||
|
TABLE_HISTORY_JOIN_IMAGES);
|
||||||
|
|
||||||
|
createMobileBookmarksFolder(db);
|
||||||
|
|
||||||
// FIXME: Create default bookmarks here
|
// FIXME: Create default bookmarks here
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createMobileBookmarksFolder(SQLiteDatabase db) {
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(Bookmarks.GUID, Bookmarks.MOBILE_FOLDER_GUID);
|
||||||
|
values.put(Bookmarks.IS_FOLDER, 1);
|
||||||
|
values.put(Bookmarks.POSITION, 0);
|
||||||
|
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
values.put(Bookmarks.DATE_CREATED, now);
|
||||||
|
values.put(Bookmarks.DATE_MODIFIED, now);
|
||||||
|
|
||||||
|
db.insertOrThrow(TABLE_BOOKMARKS, Bookmarks.GUID, values);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||||
Log.d(LOGTAG, "Upgrading browser.db: " + db.getPath() + " from " +
|
Log.d(LOGTAG, "Upgrading browser.db: " + db.getPath() + " from " +
|
||||||
@ -428,11 +470,8 @@ public class BrowserProvider extends ContentProvider {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
String isDeletedColumn = qualifyColumnValue(tableName, SyncColumns.IS_DELETED);
|
String selection = SyncColumns.IS_DELETED + " = 1 AND " +
|
||||||
String dateModifiedColumn = qualifyColumnValue(tableName, SyncColumns.DATE_MODIFIED);
|
SyncColumns.DATE_MODIFIED + " <= " + (now - MAX_AGE_OF_DELETED_RECORDS);
|
||||||
|
|
||||||
String selection = isDeletedColumn + " = 1 AND " +
|
|
||||||
dateModifiedColumn + " <= " + (now - MAX_AGE_OF_DELETED_RECORDS);
|
|
||||||
|
|
||||||
cursor = query(uriWithArgs,
|
cursor = query(uriWithArgs,
|
||||||
new String[] { CommonColumns._ID },
|
new String[] { CommonColumns._ID },
|
||||||
@ -801,22 +840,18 @@ public class BrowserProvider extends ContentProvider {
|
|||||||
|
|
||||||
if (match == BOOKMARKS_ID) {
|
if (match == BOOKMARKS_ID) {
|
||||||
Log.d(LOGTAG, "Query is BOOKMARKS_ID: " + uri);
|
Log.d(LOGTAG, "Query is BOOKMARKS_ID: " + uri);
|
||||||
selection = concatenateWhere(selection,
|
selection = concatenateWhere(selection, Bookmarks._ID + " = ?");
|
||||||
qualifyColumnValue(TABLE_BOOKMARKS, Bookmarks._ID) + " = ?");
|
|
||||||
selectionArgs = appendSelectionArgs(selectionArgs,
|
selectionArgs = appendSelectionArgs(selectionArgs,
|
||||||
new String[] { Long.toString(ContentUris.parseId(uri)) });
|
new String[] { Long.toString(ContentUris.parseId(uri)) });
|
||||||
} else if (match == BOOKMARKS_FOLDER_ID) {
|
} else if (match == BOOKMARKS_FOLDER_ID) {
|
||||||
Log.d(LOGTAG, "Query is BOOKMARKS_FOLDER_ID: " + uri);
|
Log.d(LOGTAG, "Query is BOOKMARKS_FOLDER_ID: " + uri);
|
||||||
selection = concatenateWhere(selection,
|
selection = concatenateWhere(selection, Bookmarks.PARENT + " = ?");
|
||||||
qualifyColumnValue(TABLE_BOOKMARKS, Bookmarks.PARENT) + " = ?");
|
|
||||||
selectionArgs = appendSelectionArgs(selectionArgs,
|
selectionArgs = appendSelectionArgs(selectionArgs,
|
||||||
new String[] { Long.toString(ContentUris.parseId(uri)) });
|
new String[] { Long.toString(ContentUris.parseId(uri)) });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!shouldShowDeleted(uri)) {
|
if (!shouldShowDeleted(uri))
|
||||||
String isDeletedColumn = qualifyColumnValue(TABLE_BOOKMARKS, Bookmarks.IS_DELETED);
|
selection = concatenateWhere(Bookmarks.IS_DELETED + " = 0", selection);
|
||||||
selection = concatenateWhere(isDeletedColumn + " = 0", selection);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TextUtils.isEmpty(sortOrder)) {
|
if (TextUtils.isEmpty(sortOrder)) {
|
||||||
Log.d(LOGTAG, "Using default sort order on query: " + uri);
|
Log.d(LOGTAG, "Using default sort order on query: " + uri);
|
||||||
@ -824,7 +859,11 @@ public class BrowserProvider extends ContentProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
qb.setProjectionMap(BOOKMARKS_PROJECTION_MAP);
|
qb.setProjectionMap(BOOKMARKS_PROJECTION_MAP);
|
||||||
qb.setTables(TABLE_BOOKMARKS_JOIN_IMAGES);
|
|
||||||
|
if (hasImagesInProjection(projection))
|
||||||
|
qb.setTables(VIEW_BOOKMARKS_WITH_IMAGES);
|
||||||
|
else
|
||||||
|
qb.setTables(TABLE_BOOKMARKS);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -835,22 +874,23 @@ public class BrowserProvider extends ContentProvider {
|
|||||||
|
|
||||||
if (match == HISTORY_ID) {
|
if (match == HISTORY_ID) {
|
||||||
Log.d(LOGTAG, "Query is HISTORY_ID: " + uri);
|
Log.d(LOGTAG, "Query is HISTORY_ID: " + uri);
|
||||||
selection = concatenateWhere(selection,
|
selection = concatenateWhere(selection, History._ID + " = ?");
|
||||||
qualifyColumnValue(TABLE_HISTORY, History._ID) + " = ?");
|
|
||||||
selectionArgs = appendSelectionArgs(selectionArgs,
|
selectionArgs = appendSelectionArgs(selectionArgs,
|
||||||
new String[] { Long.toString(ContentUris.parseId(uri)) });
|
new String[] { Long.toString(ContentUris.parseId(uri)) });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!shouldShowDeleted(uri)) {
|
if (!shouldShowDeleted(uri))
|
||||||
String isDeletedColumn = qualifyColumnValue(TABLE_HISTORY, History.IS_DELETED);
|
selection = concatenateWhere(History.IS_DELETED + " = 0", selection);
|
||||||
selection = concatenateWhere(isDeletedColumn + " = 0", selection);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TextUtils.isEmpty(sortOrder))
|
if (TextUtils.isEmpty(sortOrder))
|
||||||
sortOrder = DEFAULT_HISTORY_SORT_ORDER;
|
sortOrder = DEFAULT_HISTORY_SORT_ORDER;
|
||||||
|
|
||||||
qb.setProjectionMap(HISTORY_PROJECTION_MAP);
|
qb.setProjectionMap(HISTORY_PROJECTION_MAP);
|
||||||
qb.setTables(TABLE_HISTORY_JOIN_IMAGES);
|
|
||||||
|
if (hasImagesInProjection(projection))
|
||||||
|
qb.setTables(VIEW_HISTORY_WITH_IMAGES);
|
||||||
|
else
|
||||||
|
qb.setTables(TABLE_HISTORY);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -861,16 +901,13 @@ public class BrowserProvider extends ContentProvider {
|
|||||||
|
|
||||||
if (match == IMAGES_ID) {
|
if (match == IMAGES_ID) {
|
||||||
Log.d(LOGTAG, "Query is IMAGES_ID: " + uri);
|
Log.d(LOGTAG, "Query is IMAGES_ID: " + uri);
|
||||||
selection = concatenateWhere(selection,
|
selection = concatenateWhere(selection, Images._ID + " = ?");
|
||||||
qualifyColumnValue(TABLE_IMAGES, Images._ID) + " = ?");
|
|
||||||
selectionArgs = appendSelectionArgs(selectionArgs,
|
selectionArgs = appendSelectionArgs(selectionArgs,
|
||||||
new String[] { Long.toString(ContentUris.parseId(uri)) });
|
new String[] { Long.toString(ContentUris.parseId(uri)) });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!shouldShowDeleted(uri)) {
|
if (!shouldShowDeleted(uri))
|
||||||
String isDeletedColumn = qualifyColumnValue(TABLE_IMAGES, Images.IS_DELETED);
|
selection = concatenateWhere(Images.IS_DELETED + " = 0", selection);
|
||||||
selection = concatenateWhere(isDeletedColumn + " = 0", selection);
|
|
||||||
}
|
|
||||||
|
|
||||||
qb.setProjectionMap(IMAGES_PROJECTION_MAP);
|
qb.setProjectionMap(IMAGES_PROJECTION_MAP);
|
||||||
qb.setTables(TABLE_IMAGES);
|
qb.setTables(TABLE_IMAGES);
|
||||||
@ -1173,10 +1210,10 @@ public class BrowserProvider extends ContentProvider {
|
|||||||
|
|
||||||
String selection = Images.URL + " NOT IN (SELECT " + Bookmarks.URL +
|
String selection = Images.URL + " NOT IN (SELECT " + Bookmarks.URL +
|
||||||
" FROM " + TABLE_BOOKMARKS + " WHERE " + Bookmarks.URL + " IS NOT NULL AND " +
|
" FROM " + TABLE_BOOKMARKS + " WHERE " + Bookmarks.URL + " IS NOT NULL AND " +
|
||||||
qualifyColumnValue(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " = 0) AND " +
|
qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) + " = 0) AND " +
|
||||||
Images.URL + " NOT IN (SELECT " + History.URL + " FROM " + TABLE_HISTORY +
|
Images.URL + " NOT IN (SELECT " + History.URL + " FROM " + TABLE_HISTORY +
|
||||||
" WHERE " + History.URL + " IS NOT NULL AND " +
|
" WHERE " + History.URL + " IS NOT NULL AND " +
|
||||||
qualifyColumnValue(TABLE_HISTORY, History.IS_DELETED) + " = 0)";
|
qualifyColumn(TABLE_HISTORY, History.IS_DELETED) + " = 0)";
|
||||||
|
|
||||||
return deleteImages(uri, selection, null);
|
return deleteImages(uri, selection, null);
|
||||||
}
|
}
|
||||||
|
@ -65,9 +65,11 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface {
|
|||||||
public static final int TRUNCATE_N_OLDEST = 5;
|
public static final int TRUNCATE_N_OLDEST = 5;
|
||||||
|
|
||||||
private final String mProfile;
|
private final String mProfile;
|
||||||
|
private long mMobileFolderId;
|
||||||
|
|
||||||
public LocalBrowserDB(String profile) {
|
public LocalBrowserDB(String profile) {
|
||||||
mProfile = profile;
|
mProfile = profile;
|
||||||
|
mMobileFolderId = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Uri appendProfileAndLimit(Uri uri, int limit) {
|
private Uri appendProfileAndLimit(Uri uri, int limit) {
|
||||||
@ -233,10 +235,38 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface {
|
|||||||
return (count == 1);
|
return (count == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private long getMobileBookmarksFolderId(ContentResolver cr) {
|
||||||
|
if (mMobileFolderId >= 0)
|
||||||
|
return mMobileFolderId;
|
||||||
|
|
||||||
|
Cursor c = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
c = cr.query(appendProfile(Bookmarks.CONTENT_URI),
|
||||||
|
new String[] { Bookmarks._ID },
|
||||||
|
Bookmarks.GUID + " = ?",
|
||||||
|
new String[] { Bookmarks.MOBILE_FOLDER_GUID },
|
||||||
|
null);
|
||||||
|
|
||||||
|
if (c.moveToFirst())
|
||||||
|
mMobileFolderId = c.getLong(c.getColumnIndexOrThrow(Bookmarks._ID));
|
||||||
|
} finally {
|
||||||
|
if (c != null)
|
||||||
|
c.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return mMobileFolderId;
|
||||||
|
}
|
||||||
|
|
||||||
public void addBookmark(ContentResolver cr, String title, String uri) {
|
public void addBookmark(ContentResolver cr, String title, String uri) {
|
||||||
|
long folderId = getMobileBookmarksFolderId(cr);
|
||||||
|
if (folderId < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put(Browser.BookmarkColumns.TITLE, title);
|
values.put(Browser.BookmarkColumns.TITLE, title);
|
||||||
values.put(Bookmarks.URL, uri);
|
values.put(Bookmarks.URL, uri);
|
||||||
|
values.put(Bookmarks.PARENT, folderId);
|
||||||
|
|
||||||
// Restore deleted record if possible
|
// Restore deleted record if possible
|
||||||
values.put(Bookmarks.IS_DELETED, 0);
|
values.put(Bookmarks.IS_DELETED, 0);
|
||||||
|
@ -236,17 +236,17 @@ public class ViewportMetrics {
|
|||||||
|
|
||||||
public String toJSON() {
|
public String toJSON() {
|
||||||
try {
|
try {
|
||||||
return new JSONStringer().object()
|
JSONStringer object = new JSONStringer().object();
|
||||||
.key("x").value(mViewportRect.left)
|
object.key("zoom").value(mZoomFactor);
|
||||||
.key("y").value(mViewportRect.top)
|
object.key("offsetY").value(mViewportOffset.y);
|
||||||
.key("width").value(mViewportRect.width())
|
object.key("offsetX").value(mViewportOffset.x);
|
||||||
.key("height").value(mViewportRect.height())
|
object.key("pageHeight").value(mPageSize.height);
|
||||||
.key("pageWidth").value(mPageSize.width)
|
object.key("pageWidth").value(mPageSize.width);
|
||||||
.key("pageHeight").value(mPageSize.height)
|
object.key("height").value(mViewportRect.height());
|
||||||
.key("offsetX").value(mViewportOffset.x)
|
object.key("width").value(mViewportRect.width());
|
||||||
.key("offsetY").value(mViewportOffset.y)
|
object.key("y").value(mViewportRect.top);
|
||||||
.key("zoom").value(mZoomFactor)
|
object.key("x").value(mViewportRect.left);
|
||||||
.endObject().toString();
|
return object.endObject().toString();
|
||||||
} catch (JSONException je) {
|
} catch (JSONException je) {
|
||||||
Log.e(LOGTAG, "Error serializing viewportmetrics", je);
|
Log.e(LOGTAG, "Error serializing viewportmetrics", je);
|
||||||
return "";
|
return "";
|
||||||
|
@ -1160,10 +1160,10 @@ Tab.prototype = {
|
|||||||
|
|
||||||
get viewport() {
|
get viewport() {
|
||||||
// Update the viewport to current dimensions
|
// Update the viewport to current dimensions
|
||||||
this._viewport.x = this.browser.contentWindow.scrollX +
|
this._viewport.x = (this.browser.contentWindow.scrollX +
|
||||||
this.viewportExcess.x;
|
this.viewportExcess.x) || 0;
|
||||||
this._viewport.y = this.browser.contentWindow.scrollY +
|
this._viewport.y = (this.browser.contentWindow.scrollY +
|
||||||
this.viewportExcess.y;
|
this.viewportExcess.y) || 0;
|
||||||
|
|
||||||
// Transform coordinates based on zoom
|
// Transform coordinates based on zoom
|
||||||
this._viewport.x = Math.round(this._viewport.x * this._viewport.zoom);
|
this._viewport.x = Math.round(this._viewport.x * this._viewport.zoom);
|
||||||
@ -1192,8 +1192,8 @@ Tab.prototype = {
|
|||||||
updateViewport: function(aReset) {
|
updateViewport: function(aReset) {
|
||||||
let win = this.browser.contentWindow;
|
let win = this.browser.contentWindow;
|
||||||
let zoom = (aReset ? this.getDefaultZoomLevel() : this._viewport.zoom);
|
let zoom = (aReset ? this.getDefaultZoomLevel() : this._viewport.zoom);
|
||||||
let xpos = (aReset ? win.scrollX * zoom : this._viewport.x);
|
let xpos = ((aReset && win) ? win.scrollX * zoom : this._viewport.x);
|
||||||
let ypos = (aReset ? win.scrollY * zoom : this._viewport.y);
|
let ypos = ((aReset && win) ? win.scrollY * zoom : this._viewport.y);
|
||||||
|
|
||||||
this.viewportExcess = { x: 0, y: 0 };
|
this.viewportExcess = { x: 0, y: 0 };
|
||||||
this.viewport = { x: xpos, y: ypos,
|
this.viewport = { x: xpos, y: ypos,
|
||||||
|
@ -4,7 +4,7 @@ Universal manifests for Mozilla test harnesses
|
|||||||
|
|
||||||
What ManifestDestiny gives you:
|
What ManifestDestiny gives you:
|
||||||
|
|
||||||
* manifests are (ordered) lists of tests
|
* manifests are ordered lists of tests
|
||||||
* tests may have an arbitrary number of key, value pairs
|
* tests may have an arbitrary number of key, value pairs
|
||||||
* the parser returns an ordered list of test data structures, which
|
* the parser returns an ordered list of test data structures, which
|
||||||
are just dicts with some keys. For example, a test with no
|
are just dicts with some keys. For example, a test with no
|
||||||
@ -23,6 +23,14 @@ additional key, value metadata to each test.
|
|||||||
|
|
||||||
# Why have test manifests?
|
# Why have test manifests?
|
||||||
|
|
||||||
|
It is desirable to have a unified format for test manifests for testing
|
||||||
|
[mozilla-central](http://hg.mozilla.org/mozilla-central), etc.
|
||||||
|
|
||||||
|
* It is desirable to be able to selectively enable or disable tests based on platform or other conditions. This should be easy to do. Currently, since many of the harnesses just crawl directories, there is no effective way of disabling a test except for removal from mozilla-central
|
||||||
|
* It is desriable to do this in a universal way so that enabling and disabling tests as well as other tasks are easily accessible to a wider audience than just those intimately familiar with the specific test framework.
|
||||||
|
* It is desirable to have other metadata on top of the test. For instance, let's say a test is marked as skipped. It would be nice to give the reason why.
|
||||||
|
|
||||||
|
|
||||||
Most Mozilla test harnesses work by crawling a directory structure.
|
Most Mozilla test harnesses work by crawling a directory structure.
|
||||||
While this is straight-forward, manifests offer several practical
|
While this is straight-forward, manifests offer several practical
|
||||||
advantages::
|
advantages::
|
||||||
@ -37,8 +45,8 @@ advantages::
|
|||||||
removing it from the tree and a bug filed with the appropriate
|
removing it from the tree and a bug filed with the appropriate
|
||||||
reason:
|
reason:
|
||||||
|
|
||||||
[test_broken.js]
|
[test_broken.js]
|
||||||
disabled = https://bugzilla.mozilla.org/show_bug.cgi?id=123456
|
disabled = https://bugzilla.mozilla.org/show_bug.cgi?id=123456
|
||||||
|
|
||||||
* ability to run different (subsets of) tests on different
|
* ability to run different (subsets of) tests on different
|
||||||
platforms. Traditionally, we've done a bit of magic or had the test
|
platforms. Traditionally, we've done a bit of magic or had the test
|
||||||
@ -46,8 +54,8 @@ advantages::
|
|||||||
can mark what platforms a test will or will not run on and change
|
can mark what platforms a test will or will not run on and change
|
||||||
these without changing the test.
|
these without changing the test.
|
||||||
|
|
||||||
[test_works_on_windows_only.js]
|
[test_works_on_windows_only.js]
|
||||||
run-if = os == 'win'
|
run-if = os == 'win'
|
||||||
|
|
||||||
* ability to markup tests with metadata. We have a large, complicated,
|
* ability to markup tests with metadata. We have a large, complicated,
|
||||||
and always changing infrastructure. key, value metadata may be used
|
and always changing infrastructure. key, value metadata may be used
|
||||||
@ -65,32 +73,32 @@ advantages::
|
|||||||
Manifests are .ini file with the section names denoting the path
|
Manifests are .ini file with the section names denoting the path
|
||||||
relative to the manifest:
|
relative to the manifest:
|
||||||
|
|
||||||
[foo.js]
|
[foo.js]
|
||||||
[bar.js]
|
[bar.js]
|
||||||
[fleem.js]
|
[fleem.js]
|
||||||
|
|
||||||
The sections are read in order. In addition, tests may include
|
The sections are read in order. In addition, tests may include
|
||||||
arbitrary key, value metadata to be used by the harness. You may also
|
arbitrary key, value metadata to be used by the harness. You may also
|
||||||
have a `[DEFAULT]` section that will give key, value pairs that will
|
have a `[DEFAULT]` section that will give key, value pairs that will
|
||||||
be inherited by each test unless overridden:
|
be inherited by each test unless overridden:
|
||||||
|
|
||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
type = restart
|
type = restart
|
||||||
|
|
||||||
[lilies.js]
|
[lilies.js]
|
||||||
color = white
|
color = white
|
||||||
|
|
||||||
[daffodils.js]
|
[daffodils.js]
|
||||||
color = yellow
|
color = yellow
|
||||||
type = other
|
type = other
|
||||||
# override type from DEFAULT
|
# override type from DEFAULT
|
||||||
|
|
||||||
[roses.js]
|
[roses.js]
|
||||||
color = red
|
color = red
|
||||||
|
|
||||||
You can also include other manifests:
|
You can also include other manifests:
|
||||||
|
|
||||||
[include:subdir/anothermanifest.ini]
|
[include:subdir/anothermanifest.ini]
|
||||||
|
|
||||||
Manifests are included relative to the directory of the manifest with
|
Manifests are included relative to the directory of the manifest with
|
||||||
the `[include:]` directive unless they are absolute paths.
|
the `[include:]` directive unless they are absolute paths.
|
||||||
@ -109,7 +117,7 @@ terms).
|
|||||||
|
|
||||||
This data corresponds to a one-line manifest:
|
This data corresponds to a one-line manifest:
|
||||||
|
|
||||||
[testToolbar/testBackForwardButtons.js]
|
[testToolbar/testBackForwardButtons.js]
|
||||||
|
|
||||||
If additional key, values were specified, they would be in this dict
|
If additional key, values were specified, they would be in this dict
|
||||||
as well.
|
as well.
|
||||||
@ -128,13 +136,13 @@ integration layer. This should allow whatever sort of logic is
|
|||||||
desired. For instance, if in yourtestharness you wanted to run only on
|
desired. For instance, if in yourtestharness you wanted to run only on
|
||||||
mondays for a certain class of tests:
|
mondays for a certain class of tests:
|
||||||
|
|
||||||
tests = []
|
tests = []
|
||||||
for test in manifests.tests:
|
for test in manifests.tests:
|
||||||
if 'runOnDay' in test:
|
if 'runOnDay' in test:
|
||||||
if calendar.day_name[calendar.weekday(*datetime.datetime.now().timetuple()[:3])].lower() == test['runOnDay'].lower():
|
if calendar.day_name[calendar.weekday(*datetime.datetime.now().timetuple()[:3])].lower() == test['runOnDay'].lower():
|
||||||
tests.append(test)
|
tests.append(test)
|
||||||
else:
|
else:
|
||||||
tests.append(test)
|
tests.append(test)
|
||||||
|
|
||||||
To recap:
|
To recap:
|
||||||
* the manifests allow you to specify test data
|
* the manifests allow you to specify test data
|
||||||
@ -146,7 +154,7 @@ http://hg.mozilla.org/automation/ManifestDestiny/file/tip/manifestdestiny/tests/
|
|||||||
|
|
||||||
Additional manifest files may be included with an `[include:]` directive:
|
Additional manifest files may be included with an `[include:]` directive:
|
||||||
|
|
||||||
[include:path-to-additional-file.manifest]
|
[include:path-to-additional-file.manifest]
|
||||||
|
|
||||||
The path to included files is relative to the current manifest.
|
The path to included files is relative to the current manifest.
|
||||||
|
|
||||||
@ -183,7 +191,7 @@ in particular.
|
|||||||
|
|
||||||
A test harness will normally call `TestManifest.active_tests`:
|
A test harness will normally call `TestManifest.active_tests`:
|
||||||
|
|
||||||
def active_tests(self, exists=True, disabled=True, **tags):
|
def active_tests(self, exists=True, disabled=True, **tags):
|
||||||
|
|
||||||
The manifests are passed to the `__init__` or `read` methods with
|
The manifests are passed to the `__init__` or `read` methods with
|
||||||
appropriate arguments. `active_tests` then allows you to select the
|
appropriate arguments. `active_tests` then allows you to select the
|
||||||
@ -216,7 +224,7 @@ files. Run `manifestparser help create` for usage information.
|
|||||||
|
|
||||||
To copy tests and manifests from a source:
|
To copy tests and manifests from a source:
|
||||||
|
|
||||||
manifestparser [options] copy from_manifest to_directory -tag1 -tag2 --key1=value1 key2=value2 ...
|
manifestparser [options] copy from_manifest to_directory -tag1 -tag2 --key1=value1 key2=value2 ...
|
||||||
|
|
||||||
|
|
||||||
# Upating Tests
|
# Upating Tests
|
||||||
@ -224,7 +232,81 @@ To copy tests and manifests from a source:
|
|||||||
To update the tests associated with with a manifest from a source
|
To update the tests associated with with a manifest from a source
|
||||||
directory:
|
directory:
|
||||||
|
|
||||||
manifestparser [options] update manifest from_directory -tag1 -tag2 --key1=value1 --key2=value2 ...
|
manifestparser [options] update manifest from_directory -tag1 -tag2 --key1=value1 --key2=value2 ...
|
||||||
|
|
||||||
|
|
||||||
|
# Usage example
|
||||||
|
|
||||||
|
Here is an example of how to create manifests for a directory tree and
|
||||||
|
update the tests listed in the manifests from an external source.
|
||||||
|
|
||||||
|
## Creating Manifests
|
||||||
|
|
||||||
|
Let's say you want to make a series of manifests for a given directory structure containing `.js` test files:
|
||||||
|
|
||||||
|
testing/mozmill/tests/firefox/
|
||||||
|
testing/mozmill/tests/firefox/testAwesomeBar/
|
||||||
|
testing/mozmill/tests/firefox/testPreferences/
|
||||||
|
testing/mozmill/tests/firefox/testPrivateBrowsing/
|
||||||
|
testing/mozmill/tests/firefox/testSessionStore/
|
||||||
|
testing/mozmill/tests/firefox/testTechnicalTools/
|
||||||
|
testing/mozmill/tests/firefox/testToolbar/
|
||||||
|
testing/mozmill/tests/firefox/restartTests
|
||||||
|
|
||||||
|
You can use `manifestparser create` to do this:
|
||||||
|
|
||||||
|
$ manifestparser help create
|
||||||
|
Usage: manifestparser.py [options] create directory <directory> <...>
|
||||||
|
|
||||||
|
create a manifest from a list of directories
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-p PATTERN, --pattern=PATTERN
|
||||||
|
glob pattern for files
|
||||||
|
-i IGNORE, --ignore=IGNORE
|
||||||
|
directories to ignore
|
||||||
|
-w IN_PLACE, --in-place=IN_PLACE
|
||||||
|
Write .ini files in place; filename to write to
|
||||||
|
|
||||||
|
We only want `.js` files and we want to skip the `restartTests` directory.
|
||||||
|
We also want to write a manifest per directory, so I use the `--in-place`
|
||||||
|
option to write the manifests:
|
||||||
|
|
||||||
|
manifestparser create . -i restartTests -p '*.js' -w manifest.ini
|
||||||
|
|
||||||
|
This creates a manifest.ini per directory that we care about with the JS test files:
|
||||||
|
|
||||||
|
testing/mozmill/tests/firefox/manifest.ini
|
||||||
|
testing/mozmill/tests/firefox/testAwesomeBar/manifest.ini
|
||||||
|
testing/mozmill/tests/firefox/testPreferences/manifest.ini
|
||||||
|
testing/mozmill/tests/firefox/testPrivateBrowsing/manifest.ini
|
||||||
|
testing/mozmill/tests/firefox/testSessionStore/manifest.ini
|
||||||
|
testing/mozmill/tests/firefox/testTechnicalTools/manifest.ini
|
||||||
|
testing/mozmill/tests/firefox/testToolbar/manifest.ini
|
||||||
|
|
||||||
|
The top-level `manifest.ini` merely has `[include:]` references to the sub manifests:
|
||||||
|
|
||||||
|
[include:testAwesomeBar/manifest.ini]
|
||||||
|
[include:testPreferences/manifest.ini]
|
||||||
|
[include:testPrivateBrowsing/manifest.ini]
|
||||||
|
[include:testSessionStore/manifest.ini]
|
||||||
|
[include:testTechnicalTools/manifest.ini]
|
||||||
|
[include:testToolbar/manifest.ini]
|
||||||
|
|
||||||
|
Each sub-level manifest contains the (`.js`) test files relative to it.
|
||||||
|
|
||||||
|
## Updating the tests from manifests
|
||||||
|
|
||||||
|
You may need to update tests as given in manifests from a different source directory.
|
||||||
|
`manifestparser update` was made for just this purpose:
|
||||||
|
|
||||||
|
Usage: manifestparser [options] update manifest directory -tag1 -tag2 --key1=value1 --key2=value2 ...
|
||||||
|
|
||||||
|
update the tests as listed in a manifest from a directory
|
||||||
|
|
||||||
|
To update from a directory of tests in `~/mozmill/src/mozmill-tests/firefox/` run:
|
||||||
|
|
||||||
|
manifestparser update manifest.ini ~/mozmill/src/mozmill-tests/firefox/
|
||||||
|
|
||||||
|
|
||||||
# Tests
|
# Tests
|
||||||
@ -252,20 +334,20 @@ Run `manifestparser help` for usage information.
|
|||||||
|
|
||||||
To create a manifest from a set of directories:
|
To create a manifest from a set of directories:
|
||||||
|
|
||||||
manifestparser [options] create directory <directory> <...> [create-options]
|
manifestparser [options] create directory <directory> <...> [create-options]
|
||||||
|
|
||||||
To output a manifest of tests:
|
To output a manifest of tests:
|
||||||
|
|
||||||
manifestparser [options] write manifest <manifest> <...> -tag1 -tag2 --key1=value1 --key2=value2 ...
|
manifestparser [options] write manifest <manifest> <...> -tag1 -tag2 --key1=value1 --key2=value2 ...
|
||||||
|
|
||||||
To copy tests and manifests from a source:
|
To copy tests and manifests from a source:
|
||||||
|
|
||||||
manifestparser [options] copy from_manifest to_manifest -tag1 -tag2 --key1=value1 key2=value2 ...
|
manifestparser [options] copy from_manifest to_manifest -tag1 -tag2 --key1=value1 key2=value2 ...
|
||||||
|
|
||||||
To update the tests associated with with a manifest from a source
|
To update the tests associated with with a manifest from a source
|
||||||
directory:
|
directory:
|
||||||
|
|
||||||
manifestparser [options] update manifest from_directory -tag1 -tag2 --key1=value1 --key2=value2 ...
|
manifestparser [options] update manifest from_directory -tag1 -tag2 --key1=value1 --key2=value2 ...
|
||||||
|
|
||||||
|
|
||||||
# Design Considerations
|
# Design Considerations
|
||||||
@ -309,6 +391,14 @@ through several design considerations.
|
|||||||
installation.
|
installation.
|
||||||
|
|
||||||
|
|
||||||
|
# Developing ManifestDestiny
|
||||||
|
|
||||||
|
ManifestDestiny is developed and maintained by Mozilla's
|
||||||
|
[Automation and Testing Team](https://wiki.mozilla.org/Auto-tools).
|
||||||
|
The project page is located at
|
||||||
|
https://wiki.mozilla.org/Auto-tools/Projects/ManifestDestiny .
|
||||||
|
|
||||||
|
|
||||||
# Historical Reference
|
# Historical Reference
|
||||||
|
|
||||||
Date-ordered list of links about how manifests came to be where they are today::
|
Date-ordered list of links about how manifests came to be where they are today::
|
||||||
|
@ -3,6 +3,7 @@ from devicemanager import DeviceManager, DMError
|
|||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import tempfile
|
||||||
|
|
||||||
class DeviceManagerADB(DeviceManager):
|
class DeviceManagerADB(DeviceManager):
|
||||||
|
|
||||||
@ -13,6 +14,7 @@ class DeviceManagerADB(DeviceManager):
|
|||||||
self.retries = 0
|
self.retries = 0
|
||||||
self._sock = None
|
self._sock = None
|
||||||
self.useRunAs = False
|
self.useRunAs = False
|
||||||
|
self.useZip = False
|
||||||
self.packageName = None
|
self.packageName = None
|
||||||
if packageName == None:
|
if packageName == None:
|
||||||
if os.getenv('USER'):
|
if os.getenv('USER'):
|
||||||
@ -30,6 +32,10 @@ class DeviceManagerADB(DeviceManager):
|
|||||||
except:
|
except:
|
||||||
self.useRunAs = False
|
self.useRunAs = False
|
||||||
self.packageName = None
|
self.packageName = None
|
||||||
|
try:
|
||||||
|
self.verifyZip()
|
||||||
|
except:
|
||||||
|
self.useZip = False
|
||||||
try:
|
try:
|
||||||
# a test to see if we have root privs
|
# a test to see if we have root privs
|
||||||
files = self.listFiles("/data/data")
|
files = self.listFiles("/data/data")
|
||||||
@ -103,31 +109,41 @@ class DeviceManagerADB(DeviceManager):
|
|||||||
def pushDir(self, localDir, remoteDir):
|
def pushDir(self, localDir, remoteDir):
|
||||||
# adb "push" accepts a directory as an argument, but if the directory
|
# adb "push" accepts a directory as an argument, but if the directory
|
||||||
# contains symbolic links, the links are pushed, rather than the linked
|
# contains symbolic links, the links are pushed, rather than the linked
|
||||||
# files; we push file-by-file to get around this limitation
|
# files; we either zip/unzip or push file-by-file to get around this
|
||||||
|
# limitation
|
||||||
try:
|
try:
|
||||||
if (not self.dirExists(remoteDir)):
|
if (self.useZip):
|
||||||
self.mkDirs(remoteDir+"/x")
|
localZip = tempfile.mktemp()+".zip"
|
||||||
for root, dirs, files in os.walk(localDir, followlinks='true'):
|
remoteZip = remoteDir + "/adbdmtmp.zip"
|
||||||
relRoot = os.path.relpath(root, localDir)
|
subprocess.check_output(["zip", "-r", localZip, '.'], cwd=localDir)
|
||||||
for file in files:
|
self.pushFile(localZip, remoteZip)
|
||||||
localFile = os.path.join(root, file)
|
os.remove(localZip)
|
||||||
remoteFile = remoteDir + "/"
|
self.checkCmdAs(["shell", "unzip", "-o", remoteZip, "-d", remoteDir])
|
||||||
if (relRoot!="."):
|
self.checkCmdAs(["shell", "rm", remoteZip])
|
||||||
remoteFile = remoteFile + relRoot + "/"
|
else:
|
||||||
remoteFile = remoteFile + file
|
if (not self.dirExists(remoteDir)):
|
||||||
self.pushFile(localFile, remoteFile)
|
self.mkDirs(remoteDir+"/x")
|
||||||
for dir in dirs:
|
for root, dirs, files in os.walk(localDir, followlinks='true'):
|
||||||
targetDir = remoteDir + "/"
|
relRoot = os.path.relpath(root, localDir)
|
||||||
if (relRoot!="."):
|
for file in files:
|
||||||
targetDir = targetDir + relRoot + "/"
|
localFile = os.path.join(root, file)
|
||||||
targetDir = targetDir + dir
|
remoteFile = remoteDir + "/"
|
||||||
if (not self.dirExists(targetDir)):
|
if (relRoot!="."):
|
||||||
self.mkDir(targetDir)
|
remoteFile = remoteFile + relRoot + "/"
|
||||||
|
remoteFile = remoteFile + file
|
||||||
|
self.pushFile(localFile, remoteFile)
|
||||||
|
for dir in dirs:
|
||||||
|
targetDir = remoteDir + "/"
|
||||||
|
if (relRoot!="."):
|
||||||
|
targetDir = targetDir + relRoot + "/"
|
||||||
|
targetDir = targetDir + dir
|
||||||
|
if (not self.dirExists(targetDir)):
|
||||||
|
self.mkDir(targetDir)
|
||||||
self.checkCmdAs(["shell", "chmod", "777", remoteDir])
|
self.checkCmdAs(["shell", "chmod", "777", remoteDir])
|
||||||
return True
|
return remoteDir
|
||||||
except:
|
except:
|
||||||
print "pushing " + localDir + " to " + remoteDir + " failed"
|
print "pushing " + localDir + " to " + remoteDir + " failed"
|
||||||
return False
|
return None
|
||||||
|
|
||||||
# external function
|
# external function
|
||||||
# returns:
|
# returns:
|
||||||
@ -241,11 +257,25 @@ class DeviceManagerADB(DeviceManager):
|
|||||||
acmd = ["shell", "am","start"]
|
acmd = ["shell", "am","start"]
|
||||||
cmd = ' '.join(cmd).strip()
|
cmd = ' '.join(cmd).strip()
|
||||||
i = cmd.find(" ")
|
i = cmd.find(" ")
|
||||||
|
# SUT identifies the URL by looking for :\\ -- another strategy to consider
|
||||||
|
re_url = re.compile('^[http|file|chrome|about].*')
|
||||||
|
last = cmd.rfind(" ")
|
||||||
|
uri = ""
|
||||||
|
args = ""
|
||||||
|
if re_url.match(cmd[last:].strip()):
|
||||||
|
args = cmd[i:last].strip()
|
||||||
|
uri = cmd[last:].strip()
|
||||||
|
else:
|
||||||
|
args = cmd[i:].strip()
|
||||||
acmd.append("-n")
|
acmd.append("-n")
|
||||||
acmd.append(cmd[0:i] + "/.App")
|
acmd.append(cmd[0:i] + "/.App")
|
||||||
acmd.append("--es")
|
acmd.append("--es")
|
||||||
acmd.append("args")
|
if args != "":
|
||||||
acmd.append(cmd[i:])
|
acmd.append("args")
|
||||||
|
acmd.append(args)
|
||||||
|
if uri != "":
|
||||||
|
acmd.append("-d")
|
||||||
|
acmd.append(''.join(['\'',uri, '\'']));
|
||||||
print acmd
|
print acmd
|
||||||
self.checkCmd(acmd)
|
self.checkCmd(acmd)
|
||||||
return outputFile;
|
return outputFile;
|
||||||
@ -578,3 +608,25 @@ class DeviceManagerADB(DeviceManager):
|
|||||||
self.checkCmd(["shell", "rm", devroot + "/tmp/tmpfile"])
|
self.checkCmd(["shell", "rm", devroot + "/tmp/tmpfile"])
|
||||||
self.checkCmd(["shell", "run-as", packageName, "rm", "-r", devroot + "/sanity"])
|
self.checkCmd(["shell", "run-as", packageName, "rm", "-r", devroot + "/sanity"])
|
||||||
|
|
||||||
|
def isUnzipAvailable(self):
|
||||||
|
data = self.runCmd(["shell", "unzip"]).stdout.read()
|
||||||
|
if (re.search('Usage', data)):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def isLocalZipAvailable(self):
|
||||||
|
try:
|
||||||
|
subprocess.check_call(["zip", "-?"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def verifyZip(self):
|
||||||
|
# If "zip" can be run locally, and "unzip" can be run remotely, then pushDir
|
||||||
|
# can use these to push just one file per directory -- a significant
|
||||||
|
# optimization for large directories.
|
||||||
|
self.useZip = False
|
||||||
|
if (self.isUnzipAvailable() and self.isLocalZipAvailable()):
|
||||||
|
print "will use zip to push directories"
|
||||||
|
self.useZip = True
|
||||||
|
@ -110,31 +110,51 @@ def _extract(path, extdir=None, delete=False):
|
|||||||
If delete is set to True, deletes the bundle at path
|
If delete is set to True, deletes the bundle at path
|
||||||
Returns the list of top level files that were extracted
|
Returns the list of top level files that were extracted
|
||||||
"""
|
"""
|
||||||
|
assert not os.path.isfile(extdir), "extdir cannot be a file"
|
||||||
|
if extdir is None:
|
||||||
|
extdir = os.path.dirname(path)
|
||||||
|
elif not os.path.isdir(extdir):
|
||||||
|
os.makedirs(extdir)
|
||||||
if zipfile.is_zipfile(path):
|
if zipfile.is_zipfile(path):
|
||||||
bundle = zipfile.ZipFile(path)
|
bundle = zipfile.ZipFile(path)
|
||||||
namelist = bundle.namelist()
|
namelist = bundle.namelist()
|
||||||
|
if hasattr(bundle, 'extractall'):
|
||||||
|
bundle.extractall(path=extdir)
|
||||||
|
# zipfile.extractall doesn't exist in Python 2.5
|
||||||
|
else:
|
||||||
|
for name in namelist:
|
||||||
|
filename = os.path.realpath(os.path.join(extdir, name))
|
||||||
|
if name.endswith("/"):
|
||||||
|
os.makedirs(filename)
|
||||||
|
else:
|
||||||
|
path = os.path.dirname(filename)
|
||||||
|
if not os.path.isdir(path):
|
||||||
|
os.makedirs(path)
|
||||||
|
dest = open(filename, "wb")
|
||||||
|
dest.write(bundle.read(name))
|
||||||
|
dest.close()
|
||||||
elif tarfile.is_tarfile(path):
|
elif tarfile.is_tarfile(path):
|
||||||
bundle = tarfile.open(path)
|
bundle = tarfile.open(path)
|
||||||
namelist = bundle.getnames()
|
namelist = bundle.getnames()
|
||||||
|
if hasattr(bundle, 'extractall'):
|
||||||
|
bundle.extractall(path=extdir)
|
||||||
|
# tarfile.extractall doesn't exist in Python 2.4
|
||||||
|
else:
|
||||||
|
for name in namelist:
|
||||||
|
bundle.extract(name, path=extdir)
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
if extdir is None:
|
|
||||||
extdir = os.path.dirname(path)
|
|
||||||
elif not os.path.exists(extdir):
|
|
||||||
os.makedirs(extdir)
|
|
||||||
bundle.extractall(path=extdir)
|
|
||||||
bundle.close()
|
bundle.close()
|
||||||
if delete:
|
if delete:
|
||||||
os.remove(path)
|
os.remove(path)
|
||||||
# namelist returns paths with forward slashes even in windows
|
# namelist returns paths with forward slashes even in windows
|
||||||
top_level_files = [os.path.join(extdir, name) for name in namelist
|
top_level_files = [os.path.join(extdir, name) for name in namelist
|
||||||
if len(name.rstrip('/').split('/')) == 1]
|
if len(name.rstrip('/').split('/')) == 1]
|
||||||
# namelist doesn't include folders in windows, append these to the list
|
# namelist doesn't include folders, append these to the list
|
||||||
if mozinfo.isWin:
|
for name in namelist:
|
||||||
for name in namelist:
|
root = os.path.join(extdir, name[:name.find('/')])
|
||||||
root = name[:name.find('/')]
|
if root not in top_level_files:
|
||||||
if root not in top_level_files:
|
top_level_files.append(root)
|
||||||
top_level_files.append(root)
|
|
||||||
return top_level_files
|
return top_level_files
|
||||||
|
|
||||||
def _install_dmg(src, dest):
|
def _install_dmg(src, dest):
|
||||||
|
@ -100,10 +100,12 @@ TestSuite.prototype.loadTest = function(test) {
|
|||||||
log.log('TEST-END', test.name + ' ' + runTime + fThreshold);
|
log.log('TEST-END', test.name + ' ' + runTime + fThreshold);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error(test.name + ' | ' + e);
|
log.error(test.name + ' | ' + e);
|
||||||
log.debug(test.name + ' | Traceback:');
|
if (e['stack'] !== undefined) {
|
||||||
lines = e.stack.split('\n');
|
log.debug(test.name + ' | Traceback:');
|
||||||
for (let i = 0; i < lines.length - 1; ++i) {
|
lines = e.stack.split('\n');
|
||||||
log.debug('\t' + lines[i]);
|
for (let i = 0; i < lines.length - 1; ++i) {
|
||||||
|
log.debug('\t' + lines[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -36,6 +36,8 @@
|
|||||||
|
|
||||||
from mozprocess import ProcessHandler
|
from mozprocess import ProcessHandler
|
||||||
from pepresults import Results
|
from pepresults import Results
|
||||||
|
from time import sleep
|
||||||
|
from threading import Thread
|
||||||
import mozlog
|
import mozlog
|
||||||
import os
|
import os
|
||||||
|
|
||||||
@ -57,6 +59,13 @@ class PepProcess(ProcessHandler):
|
|||||||
self.logger = mozlog.getLogger('PEP')
|
self.logger = mozlog.getLogger('PEP')
|
||||||
results.fails[str(None)] = []
|
results.fails[str(None)] = []
|
||||||
|
|
||||||
|
def waitForQuit(self, timeout=5):
|
||||||
|
for i in range(1, timeout):
|
||||||
|
if self.proc.returncode != None:
|
||||||
|
return
|
||||||
|
sleep(1)
|
||||||
|
self.proc.kill()
|
||||||
|
|
||||||
def processOutputLine(self, line):
|
def processOutputLine(self, line):
|
||||||
"""
|
"""
|
||||||
Callback called on each line of output
|
Callback called on each line of output
|
||||||
@ -68,6 +77,11 @@ class PepProcess(ProcessHandler):
|
|||||||
# The output is generated from the Peptest extension
|
# The output is generated from the Peptest extension
|
||||||
# Format is 'PEP <LEVEL> <MSG>' where <MSG> can have multiple tokens
|
# Format is 'PEP <LEVEL> <MSG>' where <MSG> can have multiple tokens
|
||||||
# The content of <MSG> depends on the <LEVEL>
|
# The content of <MSG> depends on the <LEVEL>
|
||||||
|
if line.find('Test Suite Finished') != -1:
|
||||||
|
thread = Thread(target=self.waitForQuit)
|
||||||
|
thread.setDaemon(True) # don't hang on quit
|
||||||
|
thread.start()
|
||||||
|
|
||||||
level = tokens[1]
|
level = tokens[1]
|
||||||
if level == 'TEST-START':
|
if level == 'TEST-START':
|
||||||
results.currentTest = tokens[2].rstrip()
|
results.currentTest = tokens[2].rstrip()
|
||||||
@ -81,11 +95,12 @@ class PepProcess(ProcessHandler):
|
|||||||
threshold = 0.0
|
threshold = 0.0
|
||||||
|
|
||||||
msg = results.currentTest \
|
msg = results.currentTest \
|
||||||
+ ' | fail threshold: ' + str(threshold) \
|
+ ' | fail threshold: ' + str(threshold)
|
||||||
+ ' | metric: ' + str(metric)
|
|
||||||
if metric > threshold:
|
if metric > threshold:
|
||||||
|
msg += ' < metric: ' + str(metric)
|
||||||
self.logger.testFail(msg)
|
self.logger.testFail(msg)
|
||||||
else:
|
else:
|
||||||
|
msg += ' >= metric: ' + str(metric)
|
||||||
self.logger.testPass(msg)
|
self.logger.testPass(msg)
|
||||||
|
|
||||||
self.logger.testEnd(
|
self.logger.testEnd(
|
||||||
|
@ -68,25 +68,53 @@ def isURL(path):
|
|||||||
def extract(path, extdir=None, delete=False):
|
def extract(path, extdir=None, delete=False):
|
||||||
"""
|
"""
|
||||||
Takes in a tar or zip file and extracts it to extdir
|
Takes in a tar or zip file and extracts it to extdir
|
||||||
If extdir is not specified, extracts to path
|
If extdir is not specified, extracts to os.path.dirname(path)
|
||||||
If delete is set to True, deletes the bundle at path
|
If delete is set to True, deletes the bundle at path
|
||||||
Returns the list of top level files that were extracted
|
Returns the list of top level files that were extracted
|
||||||
"""
|
"""
|
||||||
|
assert not os.path.isfile(extdir), "extdir cannot be a file"
|
||||||
|
if extdir is None:
|
||||||
|
extdir = os.path.dirname(path)
|
||||||
|
elif not os.path.isdir(extdir):
|
||||||
|
os.makedirs(extdir)
|
||||||
if zipfile.is_zipfile(path):
|
if zipfile.is_zipfile(path):
|
||||||
bundle = zipfile.ZipFile(path)
|
bundle = zipfile.ZipFile(path)
|
||||||
namelist = bundle.namelist()
|
namelist = bundle.namelist()
|
||||||
|
if hasattr(bundle, 'extractall'):
|
||||||
|
bundle.extractall(path=extdir)
|
||||||
|
# zipfile.extractall doesn't exist in Python 2.5
|
||||||
|
else:
|
||||||
|
for name in namelist:
|
||||||
|
filename = os.path.realpath(os.path.join(extdir, name))
|
||||||
|
if name.endswith("/"):
|
||||||
|
os.makedirs(filename)
|
||||||
|
else:
|
||||||
|
path = os.path.dirname(filename)
|
||||||
|
if not os.path.isdir(path):
|
||||||
|
os.makedirs(path)
|
||||||
|
dest = open(filename, "wb")
|
||||||
|
dest.write(bundle.read(name))
|
||||||
|
dest.close()
|
||||||
elif tarfile.is_tarfile(path):
|
elif tarfile.is_tarfile(path):
|
||||||
bundle = tarfile.open(path)
|
bundle = tarfile.open(path)
|
||||||
namelist = bundle.getnames()
|
namelist = bundle.getnames()
|
||||||
|
if hasattr(bundle, 'extractall'):
|
||||||
|
bundle.extractall(path=extdir)
|
||||||
|
# tarfile.extractall doesn't exist in Python 2.4
|
||||||
|
else:
|
||||||
|
for name in namelist:
|
||||||
|
bundle.extract(name, path=extdir)
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
if extdir is None:
|
|
||||||
extdir = os.path.dirname(path)
|
|
||||||
elif not os.path.exists(extdir):
|
|
||||||
os.makedirs(extdir)
|
|
||||||
bundle.extractall(path=extdir)
|
|
||||||
bundle.close()
|
bundle.close()
|
||||||
if delete:
|
if delete:
|
||||||
os.remove(path)
|
os.remove(path)
|
||||||
return [os.path.join(extdir, name) for name in namelist
|
# namelist returns paths with forward slashes even in windows
|
||||||
if len(name.rstrip(os.sep).split(os.sep)) == 1]
|
top_level_files = [os.path.join(extdir, name) for name in namelist
|
||||||
|
if len(name.rstrip('/').split('/')) == 1]
|
||||||
|
# namelist doesn't include folders, append these to the list
|
||||||
|
for name in namelist:
|
||||||
|
root = os.path.join(extdir, name[:name.find('/')])
|
||||||
|
if root not in top_level_files:
|
||||||
|
top_level_files.append(root)
|
||||||
|
return top_level_files
|
||||||
|
@ -82,6 +82,7 @@ class Peptest():
|
|||||||
testObj = {}
|
testObj = {}
|
||||||
testObj['path'] = os.path.realpath(self.options.testPath)
|
testObj['path'] = os.path.realpath(self.options.testPath)
|
||||||
testObj['name'] = os.path.basename(self.options.testPath)
|
testObj['name'] = os.path.basename(self.options.testPath)
|
||||||
|
testObj['here'] = os.path.dirname(testObj['path'])
|
||||||
tests.append(testObj)
|
tests.append(testObj)
|
||||||
else:
|
else:
|
||||||
# a test manifest was passed in
|
# a test manifest was passed in
|
||||||
|
@ -44,12 +44,15 @@ try:
|
|||||||
except IOError:
|
except IOError:
|
||||||
description = ''
|
description = ''
|
||||||
|
|
||||||
version = "0.0"
|
version = "0.1"
|
||||||
|
|
||||||
dependencies = ['mozprofile',
|
dependencies = ['ManifestDestiny',
|
||||||
|
'mozhttpd',
|
||||||
|
'mozlog',
|
||||||
|
'mozprofile >= 0.1',
|
||||||
'mozprocess',
|
'mozprocess',
|
||||||
'mozrunner >= 3.0b3',
|
'mozrunner >= 3.0b3',
|
||||||
'mozlog']
|
]
|
||||||
|
|
||||||
setup(name='peptest',
|
setup(name='peptest',
|
||||||
version=version,
|
version=version,
|
||||||
|
Loading…
Reference in New Issue
Block a user