chromium/third_party/blink/web_tests/storage/indexeddb/lazy-index-population.html

<!DOCTYPE html>
<script src="../../resources/js-test.js"></script>
<script src="resources/shared.js"></script>
<script>

description("Verify edge cases that lazy index population in an IndexedDB implementation might reveal.");

indexedDBTest(prepareDatabase, verifyPreExistingIndex);
function prepareDatabase()
{
    connection = event.target.result;
    deleteAllObjectStores(connection);
    evalAndLog("store = connection.createObjectStore('store')");
    evalAndLog("store.createIndex('index1', 'name', {unique: true})");
}

function verifyPreExistingIndex()
{
    debug("Verify that uniqueness constraints are enforced with a pre-existing index:");
    evalAndLog("trans = connection.transaction('store', 'readwrite', {durability: 'relaxed'})");
    evalAndLog("store = trans.objectStore('store')");
    evalAndLog("request1 = store.put({name: 'bob'}, 1)");
    evalAndLog("request2 = store.put({name: 'bob'}, 2)");
    evalAndLog("state = 0");

    request1.onerror = unexpectedErrorCallback;
    request1.onsuccess = function () {
        debug("request1 received success event");
        shouldBe("++state", "1");
    };

    request2.onsuccess = unexpectedSuccessCallback;
    request2.onerror = function () {
        debug("request2 received error event");
        shouldBe("++state", "2");
    };

    trans.oncomplete = unexpectedCompleteCallback;
    trans.onabort = function () {
        debug("transaction aborted");
        shouldBe("++state", "3");
        shouldBe("trans.error.name", "'ConstraintError'");
        verifyCreateThenPut();
    };
}

function verifyCreateThenPut()
{
    debug("");
    debug("Verify that uniqueness constraints are enforced when index is created before puts:");

    evalAndLog("connection.close()");
    request = evalAndLog("indexedDB.open(dbname, 2)");
    request.onerror = verifyPutThenCreate;
    request.onblocked = unexpectedBlockedCallback;
    request.onsuccess = unexpectedSuccessCallback;
    request.onupgradeneeded = function() {
        connection = request.result;
        trans = request.transaction;

        evalAndLog("deleteAllObjectStores(connection)");

        evalAndLog("store = connection.createObjectStore('store')");
        evalAndLog("store.createIndex('index2', 'name', {unique: true})");
        evalAndLog("request1 = store.put({name: 'carol'}, 1)");
        evalAndLog("request2 = store.put({name: 'carol'}, 2)");
        evalAndLog("state = 0");

        request1.onerror = unexpectedErrorCallback;
        request1.onsuccess = function () {
            debug("request1 (index2) received success event");
            shouldBe("++state", "1");
        };

        request2.onsuccess = unexpectedSuccessCallback;
        request2.onerror = function () {
            debug("request2 (index2) received error event");
            shouldBe("++state", "2");
        };

        trans.oncomplete = unexpectedCompleteCallback;
        trans.onabort = function () {
            debug("transaction aborted");
            shouldBe("++state", "3");
            shouldBe("trans.error.name", "'ConstraintError'");
        };
    };
}

function verifyPutThenCreate()
{
    debug("");
    debug("Verify that uniqueness constraints are enforced when index is created after puts:");

    request = evalAndLog("indexedDB.open(dbname, 3)");
    request.onerror = verifyPutThenCreateThenPut;
    request.onblocked = unexpectedBlockedCallback;
    request.onsuccess = unexpectedSuccessCallback;
    request.onupgradeneeded = function() {
        connection = request.result;
        trans = request.transaction;

        evalAndLog("deleteAllObjectStores(connection)");

        evalAndLog("store = connection.createObjectStore('store')");
        evalAndLog("request1 = store.put({name: 'ted'}, 1)");
        evalAndLog("request2 = store.put({name: 'ted'}, 2)");
        evalAndLog("store.createIndex('index3', 'name', {unique: true})");
        evalAndLog("state = 0");

        request1.onerror = unexpectedErrorCallback;
        request1.onsuccess = function () {
            debug("request1 received success event");
            shouldBe("++state", "1");
        };

        request2.onerror = unexpectedErrorCallback;
        request2.onsuccess = function () {
            debug("request2 received success event");
            shouldBe("++state", "2");
        };

        trans.oncomplete = unexpectedCompleteCallback;
        trans.onabort = function () {
            debug("transaction aborted");
            shouldBe("++state", "3");
            shouldBe("trans.error.name", "'ConstraintError'");
        };
    };
}

function verifyPutThenCreateThenPut()
{
    debug("");
    debug("Verify that uniqueness constraints are enforced when index is created between puts:");

    request = evalAndLog("indexedDB.open(dbname, 4)");
    request.onerror = finishJSTest;
    request.onblocked = unexpectedBlockedCallback;
    request.onsuccess = unexpectedSuccessCallback;
    request.onupgradeneeded = function() {
        connection = request.result;
        trans = request.transaction;

        evalAndLog("deleteAllObjectStores(connection)");

        evalAndLog("store = connection.createObjectStore('store')");
        evalAndLog("request1 = store.put({name: 'alice'}, 1)");
        evalAndLog("store.createIndex('index4', 'name', {unique: true})");
        evalAndLog("request2 = store.put({name: 'alice'}, 2)");
        evalAndLog("state = 0");

        request1.onerror = unexpectedErrorCallback;
        request1.onsuccess = function () {
            debug("request1 received success event");
            shouldBe("++state", "1");
        };

        request2.onsuccess = unexpectedSuccessCallback;
        request2.onerror = function () {
            debug("request2 received error event");
            shouldBe("++state", "2");
        };

        trans.oncomplete = unexpectedCompleteCallback;
        trans.onabort = function () {
            debug("transaction aborted");
            shouldBe("++state", "3");
            shouldBe("trans.error.name", "'ConstraintError'");
        };
    };
}

</script>