Bug 460119 - Convert autocomplete feedback increase to an async query, r=dietrich

This commit is contained in:
Marco Bonardo 2008-12-04 16:41:06 +01:00
parent 64c2b71b1f
commit 4f8ca57707
2 changed files with 145 additions and 53 deletions

View File

@ -78,6 +78,7 @@
#include "nsNavBookmarks.h"
#include "nsPrintfCString.h"
#include "nsILivemarkService.h"
#include "mozIStoragePendingStatement.h"
#define NS_AUTOCOMPLETESIMPLERESULT_CONTRACTID \
"@mozilla.org/autocomplete/simple-result;1"
@ -1155,7 +1156,9 @@ nsNavHistory::AutoCompleteFeedback(PRInt32 aIndex,
rv = stmt->BindStringParameter(1, url);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->Execute();
// We do the update async and we don't care about failures
nsCOMPtr<mozIStoragePendingStatement> canceler;
rv = stmt->ExecuteAsync(nsnull, getter_AddRefs(canceler));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;

View File

@ -53,7 +53,22 @@
*/
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
let current_test = 0;
// Wait for a maximum of MAX_POLLING_TIMEOUT milliseconds before timing out
// while polling database.
// Since feedback increase is done async we must wait that the async statement
// gets executed, so we have to poll the database until data is consistent.
const MAX_POLLING_TIMEOUT = 3000;
// Get services
let histsvc = Cc["@mozilla.org/browser/nav-history-service;1"].
getService(Ci.nsINavHistoryService);
let db = Cc["@mozilla.org/browser/nav-history-service;1"].
getService(Ci.nsPIPlacesDatabase).
DBConnection;
let bhist = histsvc.QueryInterface(Ci.nsIBrowserHistory);
let obs = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
function AutoCompleteInput(aSearches) {
this.searches = aSearches;
@ -106,6 +121,9 @@ AutoCompleteInput.prototype = {
}
}
/**
* Checks that autocomplete results are ordered correctly
*/
function ensure_results(uris, searchTerm)
{
let controller = Components.classes["@mozilla.org/autocomplete/controller;1"].
@ -117,9 +135,6 @@ function ensure_results(uris, searchTerm)
controller.input = input;
// Search is asynchronous, so don't let the test finish immediately
do_test_pending();
input.onSearchComplete = function() {
do_check_eq(controller.searchStatus,
Ci.nsIAutoCompleteController.STATUS_COMPLETE_MATCH);
@ -128,28 +143,22 @@ function ensure_results(uris, searchTerm)
do_check_eq(controller.getValueAt(i), uris[i].spec);
}
// start the next test or finish testing if no more tests are available
if (current_test < (tests.length - 1)) {
current_test++;
tests[current_test]();
}
do_test_finished();
else
do_test_finished();
};
controller.startSearch(searchTerm);
}
// Get history service
try {
var histsvc = Cc["@mozilla.org/browser/nav-history-service;1"].
getService(Ci.nsINavHistoryService);
var bhist = histsvc.QueryInterface(Ci.nsIBrowserHistory);
var obs = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
} catch(ex) {
do_throw("Could not get history service\n");
}
/**
* Bump up the rank for an uri, returning the expected use_count value, we will
* use this value to poll database.
*/
function setCountRank(aURI, aCount, aRank, aSearch)
{
// Bump up the visit count for the uri
@ -169,9 +178,16 @@ function setCountRank(aURI, aCount, aRank, aSearch)
searchString: aSearch
};
// Bump up the instrumentation feedback
for (let i = 0; i < aRank; i++)
// Bump up the instrumentation feedback, calculating the target use_count
// we will reach after all updates
let targetUseCount = 0;
for (let i = 0; i < aRank; i++) {
obs.notifyObservers(thing, "autocomplete-will-enter-text", null);
targetUseCount = (targetUseCount * 0.9) + 1;
}
return Math.floor(targetUseCount);
}
let uri1 = uri("http://site.tld/1");
@ -187,84 +203,157 @@ let s0 = "";
let s1 = "si";
let s2 = "site";
let curTestItem1 = null;
let curTestItem2 = null;
let pollTime = Date.now();
let stmt = db.createStatement(
"SELECT use_count " +
"FROM moz_inputhistory " +
"WHERE input = ?1 AND place_id = " +
"(SELECT IFNULL((SELECT id FROM moz_places_temp WHERE url = ?2), " +
"(SELECT id FROM moz_places WHERE url = ?2)))");
/**
* Feedback increase is done async, this function ensures that all data have
* been written before checking the results.
*/
function poll_database(aSearch) {
if (Date.now() - pollTime > MAX_POLLING_TIMEOUT)
do_throw("*** TIMEOUT ***: The test timed out while polling database.\n");
stmt.bindUTF8StringParameter(0, curTestItem1.input);
stmt.bindUTF8StringParameter(1, curTestItem1.uri.spec);
if (!stmt.executeStep()) {
stmt.reset();
do_timeout(100, "poll_database('" + aSearch + "');");
return;
}
let useCount1 = stmt.getInt64(0);
stmt.reset();
stmt.bindUTF8StringParameter(0, curTestItem2.input);
stmt.bindUTF8StringParameter(1, curTestItem2.uri.spec);
if (!stmt.executeStep()) {
stmt.reset();
do_timeout(100, "poll_database('" + aSearch + "');");
return;
}
let useCount2 = stmt.getInt64(0);
stmt.reset();
if (useCount1 == curTestItem1.useCount && useCount2 == curTestItem2.useCount) {
// All data has been written, so we can check results
ensure_results([curTestItem1.uri, curTestItem2.uri], aSearch);
}
else {
// Some data is missing, poll again after 100ms
do_timeout(100, "poll_database('" + aSearch + "');");
}
}
/**
* Clean up database for next test
*/
function prepTest(name) {
print("Test " + name);
pollTime = Date.now();
bhist.removeAllPages();
}
let current_test = 0;
let tests = [
// Test things without a search term
function() {
prepTest("0 same count, diff rank, same term; no search");
setCountRank(uri1, c1, c1, s2);
setCountRank(uri2, c1, c2, s2);
ensure_results([uri1, uri2], s0);
let uc1 = setCountRank(uri1, c1, c1, s2);
let uc2 = setCountRank(uri2, c1, c2, s2);
curTestItem1 = { uri: uri1, input: s2, useCount: uc1 };
curTestItem2 = { uri: uri2, input: s2, useCount: uc2 };
do_timeout(100, "poll_database('" + s0 + "');");
},
function() {
prepTest("1 same count, diff rank, same term; no search");
setCountRank(uri1, c1, c2, s2);
setCountRank(uri2, c1, c1, s2);
ensure_results([uri2, uri1], s0);
let uc1 = setCountRank(uri1, c1, c2, s2);
let uc2 = setCountRank(uri2, c1, c1, s2);
curTestItem2 = {uri: uri1, input: s2, useCount: uc1};
curTestItem1 = {uri: uri2, input: s2, useCount: uc2};
do_timeout(100, "poll_database('" + s0 + "');");
},
function() {
prepTest("2 diff count, same rank, same term; no search");
setCountRank(uri1, c1, c1, s2);
setCountRank(uri2, c2, c1, s2);
ensure_results([uri1, uri2], s0);
let uc1 = setCountRank(uri1, c1, c1, s2);
let uc2 = setCountRank(uri2, c2, c1, s2);
curTestItem1 = {uri: uri1, input: s2, useCount: uc1};
curTestItem2 = {uri: uri2, input: s2, useCount: uc2};
do_timeout(100, "poll_database('" + s0 + "');");
},
function() {
prepTest("3 diff count, same rank, same term; no search");
setCountRank(uri1, c2, c1, s2);
setCountRank(uri2, c1, c1, s2);
ensure_results([uri2, uri1], s0);
let uc1 = setCountRank(uri1, c2, c1, s2);
let uc2 = setCountRank(uri2, c1, c1, s2);
curTestItem2 = {uri: uri1, input: s2, useCount: uc1};
curTestItem1 = {uri: uri2, input: s2, useCount: uc2};
do_timeout(100, "poll_database('" + s0 + "');");
},
// Test things with a search term (exact match one, partial other)
function() {
prepTest("4 same count, same rank, diff term; one exact/one partial search");
setCountRank(uri1, c1, c1, s1);
setCountRank(uri2, c1, c1, s2);
ensure_results([uri1, uri2], s1);
let uc1 = setCountRank(uri1, c1, c1, s1);
let uc2 = setCountRank(uri2, c1, c1, s2);
curTestItem1 = {uri: uri1, input: s1, useCount: uc1};
curTestItem2 = {uri: uri2, input: s2, useCount: uc2};
do_timeout(100, "poll_database('" + s1 + "');");
},
function() {
prepTest("5 same count, same rank, diff term; one exact/one partial search");
setCountRank(uri1, c1, c1, s2);
setCountRank(uri2, c1, c1, s1);
ensure_results([uri2, uri1], s1);
let uc1 = setCountRank(uri1, c1, c1, s2);
let uc2 = setCountRank(uri2, c1, c1, s1);
curTestItem2 = {uri: uri1, input: s2, useCount: uc1};
curTestItem1 = {uri: uri2, input: s1, useCount: uc2};
do_timeout(100, "poll_database('" + s1 + "');");
},
// Test things with a search term (exact match both)
function() {
prepTest("6 same count, diff rank, same term; both exact search");
setCountRank(uri1, c1, c1, s1);
setCountRank(uri2, c1, c2, s1);
ensure_results([uri1, uri2], s1);
let uc1 = setCountRank(uri1, c1, c1, s1);
let uc2 = setCountRank(uri2, c1, c2, s1);
curTestItem1 = {uri: uri1, input: s1, useCount: uc1};
curTestItem2 = {uri: uri2, input: s1, useCount: uc2};
do_timeout(100, "poll_database('" + s1 + "');");
},
function() {
prepTest("7 same count, diff rank, same term; both exact search");
setCountRank(uri1, c1, c2, s1);
setCountRank(uri2, c1, c1, s1);
ensure_results([uri2, uri1], s1);
let uc1 = setCountRank(uri1, c1, c2, s1);
let uc2 = setCountRank(uri2, c1, c1, s1);
curTestItem2 = {uri: uri1, input: s1, useCount: uc1};
curTestItem1 = {uri: uri2, input: s1, useCount: uc2};
do_timeout(100, "poll_database('" + s1 + "');");
},
// Test things with a search term (partial match both)
function() {
prepTest("8 same count, diff rank, same term; both partial search");
setCountRank(uri1, c1, c1, s2);
setCountRank(uri2, c1, c2, s2);
ensure_results([uri1, uri2], s1);
let uc1 = setCountRank(uri1, c1, c1, s2);
let uc2 = setCountRank(uri2, c1, c2, s2);
curTestItem1 = {uri: uri1, input: s2, useCount: uc1};
curTestItem2 = {uri: uri2, input: s2, useCount: uc2};
do_timeout(100, "poll_database('" + s1 + "');");
},
function() {
prepTest("9 same count, diff rank, same term; both partial search");
setCountRank(uri1, c1, c2, s2);
setCountRank(uri2, c1, c1, s2);
ensure_results([uri2, uri1], s1);
},
let uc1 = setCountRank(uri1, c1, c2, s2);
let uc2 = setCountRank(uri2, c1, c1, s2);
curTestItem2 = {uri: uri1, input: s2, useCount: uc1};
curTestItem1 = {uri: uri2, input: s2, useCount: uc2};
do_timeout(100, "poll_database('" + s1 + "');");
}
];
/**
* Test history autocomplete
* Test adapative autocomplete
*/
function run_test() {
tests[0]();
do_test_pending();
tests[current_test]();
}