Bug 625071: Implement deleteDatabase. r=bent

This commit is contained in:
Kyle Huey 2011-11-07 19:15:45 -05:00
parent 02524a04aa
commit 2212aeceae
10 changed files with 454 additions and 53 deletions

View File

@ -141,7 +141,8 @@ CheckPermissionsHelper::Run()
NS_ENSURE_SUCCESS(rv, rv);
}
}
else if (permission == nsIPermissionManager::UNKNOWN_ACTION) {
else if (permission == nsIPermissionManager::UNKNOWN_ACTION &&
mPromptAllowed) {
nsCOMPtr<nsIObserverService> obs = GetObserverService();
rv = obs->NotifyObservers(static_cast<nsIRunnable*>(this),
TOPIC_PERMISSIONS_PROMPT, nsnull);
@ -196,6 +197,7 @@ CheckPermissionsHelper::Observe(nsISupports* aSubject,
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(!strcmp(aTopic, TOPIC_PERMISSIONS_RESPONSE), "Bad topic!");
NS_ASSERTION(mPromptAllowed, "How did we get here?");
mHasPrompted = true;

View File

@ -64,10 +64,14 @@ public:
CheckPermissionsHelper(OpenDatabaseHelper* aHelper,
nsIDOMWindow* aWindow,
const nsACString& aASCIIOrigin)
const nsACString& aASCIIOrigin,
bool aForDeletion)
: mHelper(aHelper),
mWindow(aWindow),
mASCIIOrigin(aASCIIOrigin),
// If we're trying to delete the database, we should never prompt the user.
// Anything that would prompt is translated to denied.
mPromptAllowed(!aForDeletion),
mHasPrompted(false),
mPromptResult(0)
{
@ -80,6 +84,7 @@ private:
nsRefPtr<OpenDatabaseHelper> mHelper;
nsCOMPtr<nsIDOMWindow> mWindow;
nsCString mASCIIOrigin;
bool mPromptAllowed;
bool mHasPrompted;
PRUint32 mPromptResult;
};

View File

@ -377,19 +377,14 @@ NS_INTERFACE_MAP_END
DOMCI_DATA(IDBFactory, IDBFactory)
NS_IMETHODIMP
IDBFactory::Open(const nsAString& aName,
PRInt64 aVersion,
JSContext* aCx,
PRUint8 aOptionalArgCount,
nsIIDBOpenDBRequest** _retval)
nsresult
IDBFactory::OpenCommon(const nsAString& aName,
PRInt64 aVersion,
bool aDeleting,
nsIIDBOpenDBRequest** _retval)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (aVersion < 1 && aOptionalArgCount) {
return NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR;
}
if (XRE_GetProcessType() == GeckoProcessType_Content) {
// Force ContentChild to cache the path from the parent, so that
// we do not end up in a side thread that asks for the path (which
@ -431,13 +426,13 @@ IDBFactory::Open(const nsAString& aName,
NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
nsRefPtr<OpenDatabaseHelper> openHelper =
new OpenDatabaseHelper(request, aName, origin, aVersion);
new OpenDatabaseHelper(request, aName, origin, aVersion, aDeleting);
rv = openHelper->Init();
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
nsRefPtr<CheckPermissionsHelper> permissionHelper =
new CheckPermissionsHelper(openHelper, window, origin);
new CheckPermissionsHelper(openHelper, window, origin, aDeleting);
nsRefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::GetOrCreate();
NS_ENSURE_TRUE(mgr, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@ -448,3 +443,23 @@ IDBFactory::Open(const nsAString& aName,
request.forget(_retval);
return NS_OK;
}
NS_IMETHODIMP
IDBFactory::Open(const nsAString& aName,
PRInt64 aVersion,
PRUint8 aArgc,
nsIIDBOpenDBRequest** _retval)
{
if (aVersion < 1 && aArgc) {
return NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR;
}
return OpenCommon(aName, aVersion, false, _retval);
}
NS_IMETHODIMP
IDBFactory::DeleteDatabase(const nsAString& aName,
nsIIDBOpenDBRequest** _retval)
{
return OpenCommon(aName, 0, true, _retval);
}

View File

@ -98,6 +98,12 @@ private:
IDBFactory();
~IDBFactory() { }
nsresult
OpenCommon(const nsAString& aName,
PRInt64 aVersion,
bool aDeleting,
nsIIDBOpenDBRequest** _retval);
nsCOMPtr<nsIWeakReference> mWindow;
};

View File

@ -476,9 +476,12 @@ CreateDatabaseConnection(const nsAString& aName,
return NS_OK;
}
class VersionChangeEventsRunnable;
class SetVersionHelper : public AsyncConnectionHelper,
public IDBTransactionListener
{
friend class VersionChangeEventsRunnable;
public:
SetVersionHelper(IDBTransaction* aTransaction,
IDBOpenDBRequest* aRequest,
@ -498,9 +501,6 @@ public:
nsresult GetSuccessResult(JSContext* aCx,
jsval* aVal);
static
void QueueVersionChange(nsTArray<nsRefPtr<IDBDatabase> >& aDatabases,
void* aClosure);
protected:
nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
nsresult Init();
@ -514,6 +514,11 @@ protected:
nsresult NotifyTransactionComplete(IDBTransaction* aTransaction);
PRUint64 RequestedVersion() const
{
return mRequestedVersion;
}
private:
// In-params
nsRefPtr<OpenDatabaseHelper> mOpenHelper;
@ -522,6 +527,52 @@ private:
PRUint64 mCurrentVersion;
};
class DeleteDatabaseHelper : public AsyncConnectionHelper
{
friend class VersionChangeEventsRunnable;
public:
DeleteDatabaseHelper(IDBOpenDBRequest* aRequest,
OpenDatabaseHelper* aHelper,
PRUint64 aCurrentVersion,
const nsAString& aName,
const nsACString& aASCIIOrigin)
: AsyncConnectionHelper(static_cast<IDBDatabase*>(nsnull), aRequest),
mOpenRequest(aRequest), mOpenHelper(aHelper),
mCurrentVersion(aCurrentVersion), mName(aName),
mASCIIOrigin(aASCIIOrigin)
{ }
nsresult GetSuccessResult(JSContext* aCx,
jsval* aVal);
protected:
nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
nsresult Init();
// DeleteDatabaseHelper never fires events at the request. It hands that
// responsibility back to the OpenDatabaseHelper
void OnError()
{
mOpenHelper->NotifyDeleteFinished();
}
nsresult OnSuccess()
{
return mOpenHelper->NotifyDeleteFinished();
}
PRUint64 RequestedVersion() const
{
return 0;
}
private:
// In-params
nsRefPtr<OpenDatabaseHelper> mOpenHelper;
nsRefPtr<IDBOpenDBRequest> mOpenRequest;
PRUint64 mCurrentVersion;
nsString mName;
nsCString mASCIIOrigin;
};
// Responsible for firing "versionchange" events at all live and non-closed
// databases, and for firing a "blocked" event at the requesting database if any
// databases fail to close.
@ -599,6 +650,10 @@ public:
return NS_OK;
}
template <class T>
static
void QueueVersionChange(nsTArray<nsRefPtr<IDBDatabase> >& aDatabases,
void* aClosure);
private:
nsRefPtr<IDBDatabase> mRequestingDatabase;
nsRefPtr<IDBOpenDBRequest> mRequest;
@ -745,6 +800,11 @@ OpenDatabaseHelper::DoDatabaseWork()
mLastObjectStoreId = NS_MAX(objectStoreInfo->id, mLastObjectStoreId);
}
if (mForDeletion) {
mState = eDeletePending;
return NS_OK;
}
// See if we need to do a VERSION_CHANGE transaction
// Optional version semantics.
@ -797,7 +857,7 @@ OpenDatabaseHelper::StartSetVersion()
NS_ASSERTION(mgr, "This should never be null!");
rv = mgr->AcquireExclusiveAccess(mDatabase, helper,
&SetVersionHelper::QueueVersionChange,
&VersionChangeEventsRunnable::QueueVersionChange<SetVersionHelper>,
helper);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@ -808,6 +868,35 @@ OpenDatabaseHelper::StartSetVersion()
return NS_OK;
}
nsresult
OpenDatabaseHelper::StartDelete()
{
NS_ASSERTION(mState == eDeletePending, "Why are we here?");
// In case we fail, fire error events
mState = eFiringEvents;
nsresult rv = EnsureSuccessResult();
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<DeleteDatabaseHelper> helper =
new DeleteDatabaseHelper(mOpenDBRequest, this, mCurrentVersion, mName,
mASCIIOrigin);
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
NS_ASSERTION(mgr, "This should never be null!");
rv = mgr->AcquireExclusiveAccess(mDatabase, helper,
&VersionChangeEventsRunnable::QueueVersionChange<DeleteDatabaseHelper>,
helper);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
// The DeleteDatabaseHelper is responsible for dispatching us back to the
// main thread again and changing the state to eDeleteCompleted.
mState = eDeletePending;
return NS_OK;
}
NS_IMETHODIMP
OpenDatabaseHelper::Run()
{
@ -825,30 +914,58 @@ OpenDatabaseHelper::Run()
SetError(rv);
// fall through and run the default error processing
}
else if (mState == eDeletePending) {
nsresult rv = StartDelete();
if (NS_SUCCEEDED(rv)) {
return rv;
}
SetError(rv);
// fall through and run the default error processing
}
// We've done whatever work we need to do on the DB thread, and any
// SetVersion stuff is done by now.
// SetVersion/DeleteDatabase stuff is done by now.
NS_ASSERTION(mState == eFiringEvents ||
mState == eSetVersionCompleted, "Why are we here?");
mState == eSetVersionCompleted ||
mState == eDeleteCompleted, "Why are we here?");
if (mState == eSetVersionCompleted) {
// Allow transaction creation/other version change transactions to proceed
// before we fire events. Other version changes will be postd to the end
// of the event loop, and will be behind whatever the page does in
// its error/success event handlers.
mDatabase->ExitSetVersionTransaction();
switch (mState) {
case eSetVersionCompleted: {
// Allow transaction creation/other version change transactions to proceed
// before we fire events. Other version changes will be postd to the end
// of the event loop, and will be behind whatever the page does in
// its error/success event handlers.
mDatabase->ExitSetVersionTransaction();
mState = eFiringEvents;
} else {
// Notify the request that we're done, but only if we didn't just finish
// a SetVersionHelper. In the SetVersionHelper case, that helper tells
// the request that it is done, and we avoid calling NotifyHandlerCompleted
// twice.
nsresult rv = mOpenDBRequest->NotifyHelperCompleted(this);
if (NS_SUCCEEDED(mResultCode) && NS_FAILED(rv)) {
mResultCode = rv;
mState = eFiringEvents;
break;
}
case eDeleteCompleted: {
// Destroy the database now (we should have the only ref).
mDatabase = nsnull;
mState = eFiringEvents;
break;
}
case eFiringEvents: {
// Notify the request that we're done, but only if we didn't just
// finish a [SetVersion/DeleteDatabase]Helper. In that case, the
// helper tells the request that it is done, and we avoid calling
// NotifyHelperCompleted twice.
nsresult rv = mOpenDBRequest->NotifyHelperCompleted(this);
if (NS_SUCCEEDED(mResultCode) && NS_FAILED(rv)) {
mResultCode = rv;
}
break;
}
default:
NS_NOTREACHED("Shouldn't get here!");
}
NS_ASSERTION(mState == eFiringEvents, "Why are we here?");
@ -996,6 +1113,18 @@ OpenDatabaseHelper::NotifySetVersionFinished()
return NS_DispatchToCurrentThread(this);
}
nsresult
OpenDatabaseHelper::NotifyDeleteFinished()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread");
NS_ASSERTION(mState == eDeletePending, "How did we get here?");
mState = eDeleteCompleted;
// Dispatch ourself back to the main thread
return NS_DispatchToCurrentThread(this);
}
void
OpenDatabaseHelper::BlockDatabase()
{
@ -1008,8 +1137,6 @@ OpenDatabaseHelper::BlockDatabase()
void
OpenDatabaseHelper::DispatchSuccessEvent()
{
NS_ASSERTION(mDatabase, "Doesn't seem very successful to me.");
nsRefPtr<nsDOMEvent> event =
CreateGenericEvent(NS_LITERAL_STRING(SUCCESS_EVT_STR));
if (!event) {
@ -1104,22 +1231,23 @@ SetVersionHelper::GetSuccessResult(JSContext* aCx,
}
// static
template <class T>
void
SetVersionHelper::QueueVersionChange(nsTArray<nsRefPtr<IDBDatabase> >& aDatabases,
void* aClosure)
VersionChangeEventsRunnable::QueueVersionChange(
nsTArray<nsRefPtr<IDBDatabase> >& aDatabases,
void* aClosure)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(!aDatabases.IsEmpty(), "Why are we here?");
SetVersionHelper* helper = static_cast<SetVersionHelper*>(aClosure);
NS_ASSERTION(helper, "Why don't we have a helper?");
T* closure = static_cast<T*>(aClosure);
nsRefPtr<VersionChangeEventsRunnable> eventsRunnable =
new VersionChangeEventsRunnable(helper->mOpenHelper->Database(),
helper->mOpenRequest,
new VersionChangeEventsRunnable(closure->mOpenHelper->Database(),
closure->mOpenRequest,
aDatabases,
helper->mCurrentVersion,
helper->mRequestedVersion);
closure->mCurrentVersion,
closure->RequestedVersion());
NS_DispatchToCurrentThread(eventsRunnable);
}
@ -1158,3 +1286,41 @@ SetVersionHelper::NotifyTransactionComplete(IDBTransaction* aTransaction)
return rv;
}
nsresult
DeleteDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
{
NS_ASSERTION(!aConnection, "How did we get a connection here?");
nsCOMPtr<nsIFile> dbFile;
nsresult rv = GetDatabaseFile(mASCIIOrigin, mName, getter_AddRefs(dbFile));
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
NS_ASSERTION(dbFile, "What?");
bool exists = false;
rv = dbFile->Exists(&exists);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
if (exists) {
rv = dbFile->Remove(false);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
}
return NS_OK;
}
nsresult
DeleteDatabaseHelper::GetSuccessResult(JSContext* aCx, jsval* aVal)
{
return NS_OK;
}
nsresult
DeleteDatabaseHelper::Init()
{
// Note that there's no need to block the database here, since the page
// never gets to touch it, and all other databases must be closed.
return NS_OK;
}

View File

@ -56,13 +56,17 @@ public:
OpenDatabaseHelper(IDBOpenDBRequest* aRequest,
const nsAString& aName,
const nsACString& aASCIIOrigin,
PRUint64 aRequestedVersion)
PRUint64 aRequestedVersion,
bool aForDeletion)
: HelperBase(aRequest), mOpenDBRequest(aRequest), mName(aName),
mASCIIOrigin(aASCIIOrigin), mRequestedVersion(aRequestedVersion),
mCurrentVersion(0), mDataVersion(DB_SCHEMA_VERSION), mDatabaseId(0),
mLastObjectStoreId(0), mLastIndexId(0), mState(eCreated),
mResultCode(NS_OK)
{ }
mForDeletion(aForDeletion), mCurrentVersion(0),
mDataVersion(DB_SCHEMA_VERSION), mDatabaseId(0), mLastObjectStoreId(0),
mLastIndexId(0), mState(eCreated), mResultCode(NS_OK)
{
NS_ASSERTION(!aForDeletion || !aRequestedVersion,
"Can't be for deletion and request a version!");
}
NS_DECL_ISUPPORTS
NS_DECL_NSIRUNNABLE
@ -84,6 +88,7 @@ public:
}
nsresult NotifySetVersionFinished();
nsresult NotifyDeleteFinished();
void BlockDatabase();
nsIAtom* Id() const
@ -101,6 +106,7 @@ protected:
// Methods only called on the main thread
nsresult EnsureSuccessResult();
nsresult StartSetVersion();
nsresult StartDelete();
nsresult GetSuccessResult(JSContext* aCx,
jsval* aVal);
void DispatchSuccessEvent();
@ -116,6 +122,7 @@ private:
nsString mName;
nsCString mASCIIOrigin;
PRUint64 mRequestedVersion;
bool mForDeletion;
nsCOMPtr<nsIAtom> mDatabaseId;
// Out-params.
@ -134,6 +141,8 @@ private:
eFiringEvents, // Waiting to fire/firing events on the main thread
eSetVersionPending, // Waiting on a SetVersionHelper
eSetVersionCompleted, // SetVersionHelper is done
eDeletePending, // Waiting on a DeleteDatabaseHelper
eDeleteCompleted, // DeleteDatabaseHelper is done
};
OpenDatabaseState mState;
nsresult mResultCode;

View File

@ -48,11 +48,14 @@ interface nsIIDBOpenDBRequest;
* http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBFactory
* for more information.
*/
[scriptable, builtinclass, uuid(aaf95f14-f858-4f86-9369-79bf3c06b6c8)]
[scriptable, builtinclass, uuid(885abbb7-cf81-4945-b5f1-07fed07ada82)]
interface nsIIDBFactory : nsISupports
{
[implicit_jscontext, optional_argc]
[optional_argc]
nsIIDBOpenDBRequest
open([Null(Stringify)] in DOMString name,
[optional] in long long version);
nsIIDBOpenDBRequest
deleteDatabase(in AString name);
};

View File

@ -65,6 +65,8 @@ TEST_FILES = \
test_cursors.html \
test_cursor_mutation.html \
test_cursor_update_updates_indexes.html \
test_deleteDatabase.html \
test_deleteDatabase_interactions.html \
test_error_events_abort_transactions.html \
test_event_propagation.html \
test_event_source.html \

View File

@ -0,0 +1,114 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>Indexed Database DeleteDatabase 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 READ_WRITE = Components.interfaces.nsIIDBTransaction.READ_WRITE;
const VERSION_CHANGE = Components.interfaces.nsIIDBTransaction.VERSION_CHANGE;
const name = window.location.pathname;
ok(mozIndexedDB.deleteDatabase, "deleteDatabase function should exist!");
let request = mozIndexedDB.open(name, 10);
request.onerror = errorHandler;
request.onsuccess = unexpectedSuccessHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
ok(request instanceof IDBOpenDBRequest, "Expect an IDBOpenDBRequest");
let event = yield;
is(event.type, "upgradeneeded", "Expect an upgradeneeded event");
ok(event instanceof IDBVersionChangeEvent, "Expect a versionchange event");
let db = event.target.result;
db.createObjectStore("stuff");
request.onsuccess = grabEventAndContinueHandler;
event = yield;
is(event.type, "success", "Expect a success event");
is(event.target, request, "Event has right target");
ok(event.target.result instanceof IDBDatabase, "Result should be a database");
is(db.objectStoreNames.length, 1, "Expect an objectStore here");
let request = mozIndexedDB.open(name, 10);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
is(event.type, "success", "Expect a success event");
is(event.target, request, "Event has right target");
ok(event.target.result instanceof IDBDatabase, "Result should be a database");
let db2 = event.target.result;
is(db2.objectStoreNames.length, 1, "Expect an objectStore here");
var onversionchangecalled = false;
function closeDBs(event) {
onversionchangecalled = true;
ok(event instanceof IDBVersionChangeEvent, "expect a versionchange event");
is(event.oldVersion, 10, "oldVersion should be 10");
todo(event.newVersion, null, "newVersion should be null");
db.close();
db2.close();
db.onversionchange = errorHandler;
db2.onversionchange = errorHandler;
};
// The IDB spec doesn't guarantee the order that onversionchange will fire
// on the dbs.
db.onversionchange = closeDBs;
db2.onversionchange = closeDBs;
let request = mozIndexedDB.deleteDatabase(name);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
ok(request instanceof IDBOpenDBRequest, "Expect an IDBOpenDBRequest");
event = yield;
ok(onversionchangecalled, "Expected versionchange events");
is(event.type, "success", "expect a success event");
is(event.target, request, "event has right target");
is(event.target.result, null, "event should have no result");
let request = mozIndexedDB.open(name, 1);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
is(event.target.result.version, 1, "DB has proper version");
is(event.target.result.objectStoreNames.length, 0, "DB should have no object stores");
let request = mozIndexedDB.deleteDatabase("thisDatabaseHadBetterNotExist");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
ok(true, "deleteDatabase on a non-existent database succeeded");
finishTest();
yield;
}
</script>
<script type="text/javascript;version=1.7" src="helpers.js"></script>
</head>
<body onload="runTest();"></body>
</html>

View File

@ -0,0 +1,79 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>Indexed Database DeleteDatabase 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 READ_WRITE = Components.interfaces.nsIIDBTransaction.READ_WRITE;
const VERSION_CHANGE = Components.interfaces.nsIIDBTransaction.VERSION_CHANGE;
const name = window.location.pathname;
let request = mozIndexedDB.open(name, 10);
request.onerror = errorHandler;
request.onsuccess = unexpectedSuccessHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
ok(request instanceof IDBOpenDBRequest, "Expect an IDBOpenDBRequest");
let event = yield;
is(event.type, "upgradeneeded", "Expect an upgradeneeded event");
ok(event instanceof IDBVersionChangeEvent, "Expect a versionchange event");
let db = event.target.result;
db.createObjectStore("stuff");
request.onsuccess = grabEventAndContinueHandler;
event = yield;
is(event.type, "success", "Expect a success event");
is(event.target, request, "Event has right target");
ok(event.target.result instanceof IDBDatabase, "Result should be a database");
is(db.objectStoreNames.length, 1, "Expect an objectStore here");
db.close();
let request = mozIndexedDB.deleteDatabase(name);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
ok(request instanceof IDBOpenDBRequest, "Expect an IDBOpenDBRequest");
let openRequest = mozIndexedDB.open(name, 1);
openRequest.onerror = errorHandler;
openRequest.onsuccess = unexpectedSuccessHandler;
event = yield;
is(event.type, "success", "expect a success event");
is(event.target, request, "event has right target");
is(event.target.result, null, "event should have no result");
openRequest.onsuccess = grabEventAndContinueHandler;
event = yield;
is(event.target.result.version, 1, "DB has proper version");
is(event.target.result.objectStoreNames.length, 0, "DB should have no object stores");
finishTest();
yield;
}
</script>
<script type="text/javascript;version=1.7" src="helpers.js"></script>
</head>
<body onload="runTest();"></body>
</html>