This commit is contained in:
Ryan VanderMeulen 2012-05-21 20:37:54 -04:00
Родитель 64f68cedd4 6b1a01cb30
Коммит 4f9cad8a80
11 изменённых файлов: 346 добавлений и 107 удалений

Просмотреть файл

@ -9,106 +9,7 @@
<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;
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");
let request = mozIndexedDB.open("thisDatabaseHadBetterNotExist");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
ok(true, "after deleting a non-existent database, open should work");
finishTest();
yield;
}
</script>
<script type="text/javascript;version=1.7" src="unit/test_deleteDatabase.js"></script>
<script type="text/javascript;version=1.7" src="helpers.js"></script>
</head>

Просмотреть файл

@ -24,6 +24,7 @@ TEST_FILES = \
test_cursor_mutation.js \
test_cursor_update_updates_indexes.js \
test_cursors.js \
test_deleteDatabase.js \
test_event_source.js \
test_getAll.js \
test_global_data.js \

Просмотреть файл

@ -0,0 +1,104 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
var testGenerator = testSteps();
function testSteps()
{
const name = this.window ? window.location.pathname : "Splendid Test";
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");
ok(event.target.result === undefined, "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");
let request = mozIndexedDB.open("thisDatabaseHadBetterNotExist");
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
ok(true, "after deleting a non-existent database, open should work");
finishTest();
yield;
}

Просмотреть файл

@ -14,6 +14,7 @@ tail =
[test_cursor_mutation.js]
[test_cursor_update_updates_indexes.js]
[test_cursors.js]
[test_deleteDatabase.js]
[test_event_source.js]
[test_getAll.js]
[test_global_data.js]

Просмотреть файл

@ -318,6 +318,14 @@ SpdySession::RegisterStreamID(SpdyStream *stream)
if (mNextStreamID >= kMaxStreamID)
mShouldGoAway = true;
// integrity check
if (mStreamIDHash.Get(result)) {
LOG3((" New ID already present\n"));
NS_ABORT_IF_FALSE(false, "New ID already present in mStreamIDHash");
mShouldGoAway = true;
return kDeadStreamID;
}
mStreamIDHash.Put(result, stream);
return result;
}
@ -330,6 +338,13 @@ SpdySession::AddStream(nsAHttpTransaction *aHttpTransaction,
NS_ABORT_IF_FALSE(!mStreamTransactionHash.Get(aHttpTransaction),
"AddStream duplicate transaction pointer");
// integrity check
if (mStreamTransactionHash.Get(aHttpTransaction)) {
LOG3((" New transaction already present\n"));
NS_ABORT_IF_FALSE(false, "New transaction already present in hash");
return false;
}
aHttpTransaction->SetConnection(this);
SpdyStream *stream = new SpdyStream(aHttpTransaction,
this,
@ -822,6 +837,59 @@ SpdySession::GenerateGoAway()
FlushOutputQueue();
}
// perform a bunch of integrity checks on the stream.
// returns true if passed, false (plus LOG and ABORT) if failed.
bool
SpdySession::VerifyStream(SpdyStream *aStream, PRUint32 aOptionalID = 0)
{
// This is annoying, but at least it is O(1)
NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
if (!aStream)
return true;
PRUint32 test = 0;
do {
if (aStream->StreamID() == kDeadStreamID)
break;
nsAHttpTransaction *trans = aStream->Transaction();
test++;
if (!trans)
break;
test++;
if (mStreamTransactionHash.Get(trans) != aStream)
break;
if (aStream->StreamID()) {
SpdyStream *idStream = mStreamIDHash.Get(aStream->StreamID());
test++;
if (idStream != aStream)
break;
if (aOptionalID) {
test++;
if (idStream->StreamID() != aOptionalID)
break;
}
}
// tests passed
return true;
} while (0);
LOG(("SpdySession %p VerifyStream Failure %p stream->id=0x%x "
"optionalID=0x%x trans=%p test=%d\n",
this, aStream, aStream->StreamID(),
aOptionalID, aStream->Transaction(), test));
NS_ABORT_IF_FALSE(false, "VerifyStream");
return false;
}
void
SpdySession::CleanupStream(SpdyStream *aStream, nsresult aResult,
rstReason aResetCode)
@ -830,6 +898,11 @@ SpdySession::CleanupStream(SpdyStream *aStream, nsresult aResult,
LOG3(("SpdySession::CleanupStream %p %p 0x%x %X\n",
this, aStream, aStream->StreamID(), aResult));
if (!VerifyStream(aStream)) {
LOG(("SpdySession::CleanupStream failed to verify stream\n"));
return;
}
if (!aStream->RecvdFin() && aStream->StreamID()) {
LOG3(("Stream had not processed recv FIN, sending RST code %X\n",
aResetCode));
@ -937,6 +1010,19 @@ SpdySession::HandleSynStream(SpdySession *self)
return NS_OK;
}
nsresult
SpdySession::SetInputFrameDataStream(PRUint32 streamID)
{
mInputFrameDataStream = mStreamIDHash.Get(streamID);
if (VerifyStream(mInputFrameDataStream, streamID))
return NS_OK;
LOG(("SpdySession::SetInputFrameDataStream failed to verify 0x%X\n",
streamID));
mInputFrameDataStream = nsnull;
return NS_ERROR_UNEXPECTED;
}
nsresult
SpdySession::HandleSynReply(SpdySession *self)
{
@ -961,9 +1047,14 @@ SpdySession::HandleSynReply(SpdySession *self)
return NS_ERROR_FAILURE;
}
LOG3(("SpdySession::HandleSynReply %p lookup via streamID in syn_reply.\n",
self));
PRUint32 streamID =
PR_ntohl(reinterpret_cast<PRUint32 *>(self->mInputFrameBuffer.get())[2]);
self->mInputFrameDataStream = self->mStreamIDHash.Get(streamID);
nsresult rv = self->SetInputFrameDataStream(streamID);
if (NS_FAILED(rv))
return rv;
if (!self->mInputFrameDataStream) {
LOG3(("SpdySession::HandleSynReply %p lookup streamID in syn_reply "
"0x%X failed. NextStreamID = 0x%x", self, streamID,
@ -975,7 +1066,7 @@ SpdySession::HandleSynReply(SpdySession *self)
return NS_OK;
}
nsresult rv = self->HandleSynReplyForValidStream();
rv = self->HandleSynReplyForValidStream();
if (rv == NS_ERROR_ILLEGAL_VALUE) {
LOG3(("SpdySession::HandleSynReply %p PROTOCOL_ERROR detected 0x%X\n",
self, streamID));
@ -1085,10 +1176,17 @@ SpdySession::HandleRstStream(SpdySession *self)
return NS_OK;
}
self->mInputFrameDataStream = self->mStreamIDHash.Get(streamID);
nsresult rv = self->SetInputFrameDataStream(streamID);
if (!self->mInputFrameDataStream) {
if (NS_FAILED(rv))
LOG(("SpdySession::HandleRstStream %p lookup streamID for RST Frame "
"0x%X failed reason = %d :: VerifyStream Failed\n", self, streamID,
self->mDownstreamRstReason));
LOG3(("SpdySession::HandleRstStream %p lookup streamID for RST Frame "
"0x%X failed", self, streamID));
"0x%X failed reason = %d", self, streamID,
self->mDownstreamRstReason));
return NS_ERROR_ILLEGAL_VALUE;
}
@ -1553,7 +1651,12 @@ SpdySession::WriteSegments(nsAHttpSegmentWriter *writer,
PRUint32 streamID =
PR_ntohl(reinterpret_cast<PRUint32 *>(mInputFrameBuffer.get())[0]);
mInputFrameDataStream = mStreamIDHash.Get(streamID);
rv = SetInputFrameDataStream(streamID);
if (NS_FAILED(rv)) {
LOG(("SpdySession::WriteSegments %p lookup streamID 0x%X failed. "
"probably due to verification.\n", this, streamID));
return rv;
}
if (!mInputFrameDataStream) {
LOG3(("SpdySession::WriteSegments %p lookup streamID 0x%X failed. "
"Next = 0x%x", this, streamID, mNextStreamID));
@ -1595,6 +1698,9 @@ SpdySession::WriteSegments(nsAHttpSegmentWriter *writer,
// mInputFrameDataStream is reset by ChangeDownstreamState
SpdyStream *stream = mInputFrameDataStream;
ResetDownstreamState();
LOG3(("SpdySession::WriteSegments cleanup stream on recv of rst "
"session=%p stream=%p 0x%X\n", this, stream,
stream ? stream->StreamID() : 0));
CleanupStream(stream, rv, RST_CANCEL);
return NS_OK;
}
@ -1602,6 +1708,11 @@ SpdySession::WriteSegments(nsAHttpSegmentWriter *writer,
if (mDownstreamState == PROCESSING_DATA_FRAME ||
mDownstreamState == PROCESSING_CONTROL_SYN_REPLY) {
// The cleanup stream should only be set while stream->WriteSegments is
// on the stack and then cleaned up in this code block afterwards.
NS_ABORT_IF_FALSE(!mNeedsCleanup, "cleanup stream set unexpectedly");
mNeedsCleanup = nsnull; /* just in case */
mSegmentWriter = writer;
rv = mInputFrameDataStream->WriteSegments(this, count, countWritten);
mSegmentWriter = nsnull;
@ -1614,12 +1725,21 @@ SpdySession::WriteSegments(nsAHttpSegmentWriter *writer,
SpdyStream *stream = mInputFrameDataStream;
if (mInputFrameDataRead == mInputFrameDataSize)
ResetDownstreamState();
LOG3(("SpdySession::WriteSegments session=%p stream=%p 0x%X "
"needscleanup=%p. cleanup stream based on "
"stream->writeSegments returning BASE_STREAM_CLOSED\n",
this, stream, stream ? stream->StreamID() : 0,
mNeedsCleanup));
CleanupStream(stream, NS_OK, RST_CANCEL);
NS_ABORT_IF_FALSE(!mNeedsCleanup, "double cleanup out of data frame");
mNeedsCleanup = nsnull; /* just in case */
return NS_OK;
}
if (mNeedsCleanup) {
LOG3(("SpdySession::WriteSegments session=%p stream=%p 0x%X "
"cleanup stream based on mNeedsCleanup.\n",
this, mNeedsCleanup, mNeedsCleanup ? mNeedsCleanup->StreamID() : 0));
CleanupStream(mNeedsCleanup, NS_OK, RST_CANCEL);
mNeedsCleanup = nsnull;
}
@ -1946,7 +2066,7 @@ SpdySession::TransactionHasDataToWrite(nsAHttpTransaction *caller)
// it is no longer blocked on read.
SpdyStream *stream = mStreamTransactionHash.Get(caller);
if (!stream) {
if (!stream || !VerifyStream(stream)) {
LOG3(("SpdySession::TransactionHasDataToWrite %p caller %p not found",
this, caller));
return;

Просмотреть файл

@ -126,6 +126,10 @@ public:
const static PRUint32 kDefaultMaxConcurrent = 100;
const static PRUint32 kMaxStreamID = 0x7800000;
// This is a sentinel for a deleted stream. It is not a valid
// 31 bit stream ID.
const static PRUint32 kDeadStreamID = 0xffffdead;
static nsresult HandleSynStream(SpdySession *);
static nsresult HandleSynReply(SpdySession *);
static nsresult HandleRstStream(SpdySession *);
@ -185,6 +189,8 @@ private:
bool RoomForMoreConcurrent();
void ActivateStream(SpdyStream *);
void ProcessPending();
nsresult SetInputFrameDataStream(PRUint32);
bool VerifyStream(SpdyStream *, PRUint32);
// a wrapper for all calls to the nshttpconnection level segment writer. Used
// to track network I/O for timeout purposes

Просмотреть файл

@ -60,6 +60,7 @@ SpdyStream::SpdyStream(nsAHttpTransaction *httpTransaction,
SpdyStream::~SpdyStream()
{
mStreamID = SpdySession::kDeadStreamID;
}
// ReadSegments() is used to write data down the socket. Generally, HTTP

Просмотреть файл

@ -1179,7 +1179,7 @@ nsHttpConnectionMgr::RestrictConnections(nsConnectionEntry *ent)
bool confirmedRestrict = false;
for (PRUint32 index = 0; index < ent->mActiveConns.Length(); ++index) {
nsHttpConnection *conn = ent->mActiveConns[index];
if (!conn->ReportedNPN() || conn->EverUsedSpdy()) {
if (!conn->ReportedNPN() || conn->CanDirectlyActivate()) {
confirmedRestrict = true;
break;
}

Просмотреть файл

@ -4,4 +4,5 @@
from marionette import Marionette, HTMLElement
from marionette_test import MarionetteTestCase
from emulator import Emulator

Просмотреть файл

@ -0,0 +1,42 @@
from marionette import Marionette, Emulator
from optparse import OptionParser
def runemulator(homedir=None, url=None, pidfile=None, arch='x86'):
qemu = Emulator(homedir=homedir, arch=arch)
qemu.start()
port = qemu.setup_port_forwarding(2828)
assert(qemu.wait_for_port())
if pidfile:
f = open(pidfile, 'w')
f.write("%d" % qemu.proc.pid)
f.close()
print 'emulator launched, pid:', qemu.proc.pid
if url:
marionette = Marionette(port=port)
marionette.start_session()
marionette.navigate(url)
marionette.delete_session()
if __name__ == '__main__':
parser = OptionParser()
parser.add_option('--repo', dest='repo_path', action='store',
help='directory of the B2G repo')
parser.add_option('--arch', dest='arch', action='store',
default='x86',
help='the emulator cpu architecture (x86 or arm)')
parser.add_option('--url', dest='url', action='store',
help='url to navigate to after launching emulator')
parser.add_option('--pidfile', dest='pidfile', action='store',
help='file in which to store emulator pid')
options, args = parser.parse_args()
if not options.repo_path:
raise Exception ("must specify the --repo /path/to/B2G/repo argument")
runemulator(homedir=options.repo_path,
url=options.url,
pidfile=options.pidfile,
arch=options.arch)

Просмотреть файл

@ -0,0 +1,62 @@
#!/bin/bash
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
# Marionette requires Python 2.7, so the first parameter to this script
# should be the path to that.
PYTHON=$1
if [ -z "${PYTHON}" ]
then
echo "No python found"
exit 1
fi
# Determine the absolute path of our location.
echo $0
echo `dirname $0`
echo $PWD
SCRIPTS_HOME=`dirname $0`
cd $SCRIPTS_HOME
cd ..
MARIONETTE_HOME=`dirname $PWD`
echo "Detected Marionette home in $MARIONETTE_HOME"
# If a GECKO_OBJDIR environemnt variable exists, we will create the Python
# virtual envirnoment there. Otherwise we create it in the PWD.
VENV_DIR="runemu_venv"
if [ -z $GECKO_OBJDIR ]
then
VENV_DIR="$MARIONETTE_HOME/$VENV_DIR"
else
VENV_DIR="$GECKO_OBJDIR/$VENV_DIR"
fi
# Check if environment exists, if not, create a virtualenv:
if [ -d $VENV_DIR ]
then
echo "Using virtual environment in $VENV_DIR"
cd $VENV_DIR
. bin/activate
else
echo "Creating a virtual environment in $VENV_DIR"
curl https://raw.github.com/pypa/virtualenv/develop/virtualenv.py | ${PYTHON} - $VENV_DIR
cd $VENV_DIR
. bin/activate
# set up mozbase
git clone git://github.com/mozilla/mozbase.git
cd mozbase
python setup_development.py
fi
# update the marionette_client
cd $MARIONETTE_HOME
python setup.py develop
cd marionette
# pop off the python parameter
shift
cd scripts
python runemu.py $@