summaryrefslogtreecommitdiffstats
path: root/LayoutTests/storage/test-authorizer.html
blob: 57785a6413eca005aa45be0bfa602c4e6c2d2802 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
<html>
<head>
<script>

function log(message)
{
    document.body.innerHTML += message + "<br>";
}

function terminateTest()
{
    if (window.layoutTestController)
        layoutTestController.notifyDone();
}

function logAndTerminateTest(message, error)
{
    log(message + ": " + error.message);
    terminateTest();
}

function cleanup(db)
{
    db.transaction(function(tx) {
            tx.executeSql("DROP TABLE IF EXISTS Test;");
            tx.executeSql("DROP INDEX IF EXISTS TestIndex;");
            tx.executeSql("DROP VIEW IF EXISTS TestView;");
            tx.executeSql("DROP TRIGGER IF EXISTS TestTrigger;");
        }, function(error) { logAndTerminateTest("Cleanup failed", error); });
}

function statementSuccessCallback(statementType)
{
    log(statementType + " statement succeeded.");
}

function statementErrorCallback(statementType, error)
{
    log(statementType + " statement failed: " + error.message);
    return false;
}

function executeStatement(tx, statement, operation)
{
    tx.executeSql(statement, [],
                  function(result) { statementSuccessCallback(operation); },
                  function(tx, error) { return statementErrorCallback(operation, error); });
}

function createTableCallback(tx)
{
    executeStatement(tx, "CREATE TABLE Test (Foo int);", "SQLITE_CREATE_TABLE");
}

function createStatementsCallback(tx)
{
    executeStatement(tx, "CREATE INDEX TestIndex ON Test (Foo);", "SQLITE_CREATE_INDEX");

    // Even though the following query should trigger a SQLITE_CREATE_TEMP_INDEX operation
    // (according to http://www.sqlite.org/tempfiles.html), it doesn't, and I'm not aware
    // of any other way to trigger this operation. So we'll skip it for now.
    //executeStatement(tx, "SELECT * FROM Test WHERE Foo IN (1, 2, 3);", "SQLITE_CREATE_TEMP_INDEX");

    executeStatement(tx, "CREATE TEMP TABLE TestTempTable (Foo int);", "SQLITE_CREATE_TEMP_TABLE");
    executeStatement(tx, "CREATE TEMP TRIGGER TestTempTrigger INSERT ON Test BEGIN SELECT COUNT(*) FROM Test; END;", "SQLITE_CREATE_TEMP_TRIGGER");
    executeStatement(tx, "CREATE TEMP VIEW TestTempView AS SELECT COUNT(*) FROM Test;", "SQLITE_CREATE_TEMP_VIEW");
    executeStatement(tx, "CREATE TRIGGER TestTrigger INSERT ON Test BEGIN SELECT COUNT(*) FROM Test; END;", "SQLITE_CREATE_TRIGGER");
    executeStatement(tx, "CREATE VIEW TestView AS SELECT COUNT(*) FROM Test;", "SQLITE_CREATE_VIEW");
    executeStatement(tx, "CREATE VIRTUAL TABLE TestVirtualTable USING MissingModule;", "SQLITE_CREATE_VTABLE");
}

function otherStatementsCallback(tx)
{
    executeStatement(tx, "SELECT COUNT(*) FROM Test;", "SQLITE_READ");
    executeStatement(tx, "SELECT COUNT(*) FROM Test;", "SQLITE_SELECT");
    executeStatement(tx, "DELETE FROM Test;", "SQLITE_DELETE");
    executeStatement(tx, "INSERT INTO Test VALUES (1);", "SQLITE_INSERT");
    executeStatement(tx, "UPDATE Test SET Foo = 2 WHERE Foo = 1;", "SQLITE_UPDATE");
    executeStatement(tx, "PRAGMA cache_size;", "SQLITE_PRAGMA");

    executeStatement(tx, "ALTER TABLE Test RENAME TO TestTable;", "SQLITE_ALTER_TABLE");
    // Rename the table back to its original name
    executeStatement(tx, "ALTER TABLE TestTable RENAME To Test;", "SQLITE_ALTER_TABLE");

    executeStatement(tx, "BEGIN TRANSACTION;", "SQLITE_TRANSACTION");
    executeStatement(tx, "ATTACH main AS TestMain;", "SQLITE_ATTACH");
    executeStatement(tx, "DETACH TestMain;", "SQLITE_DETACH");
    executeStatement(tx, "REINDEX;", "SQLITE_REINDEX");
    executeStatement(tx, "ANALYZE;", "SQLITE_ANALYZE");

    // SQLITE_FUNCTION: allowed write mode
    // There is no SQL/Javascript API to add user-defined functions to SQLite,
    // so we cannot test this operation
}

function dropStatementsCallback(tx)
{
    executeStatement(tx, "DROP INDEX TestIndex;", "SQLITE_DROP_INDEX");

    // SQLITE_DROP_TEMP_INDEX: allowed in write mode
    // Not sure how to test this: temp indexes are automatically dropped when
    // the database is closed, but HTML5 doesn't specify a closeDatabase() call.

    executeStatement(tx, "DROP TABLE TestTempTable;", "SQLITE_DROP_TEMP_TABLE");
    executeStatement(tx, "DROP TRIGGER TestTempTrigger;", "SQLITE_DROP_TEMP_TRIGGER");
    executeStatement(tx, "DROP VIEW TestTempView;", "SQLITE_DROP_TEMP_VIEW");
    executeStatement(tx, "DROP TRIGGER TestTrigger;", "SQLITE_DROP_TRIGGER");
    executeStatement(tx, "DROP VIEW TestView;", "SQLITE_DROP_VIEW");

    // SQLITE_DROP_VTABLE: allowed in write mode
    // Not sure how to test this: we cannot create a virtual table because we do not
    // have SQL/Javascript APIs to register a module that implements a virtual table.
    // Therefore, trying to drop a virtual table will always fail (no such table)
    // before even getting to the authorizer.

    executeStatement(tx, "DROP TABLE Test;", "SQLITE_DROP_TABLE");
}

function testReadWriteMode(db)
{
    db.transaction(function(tx) {
            createTableCallback(tx);
            createStatementsCallback(tx);
            otherStatementsCallback(tx);
            dropStatementsCallback(tx);
        },
        function(error) { logAndTerminateTest("Write transaction failed", error); },
        function() { log("Write transaction succeeded."); });
}

function testReadOnlyMode(db)
{
    // Test the 'CREATE TABLE' operation; it should be disallowed
    db.readTransaction(createTableCallback,
        function(error) { logAndTerminateTest("Read 'CREATE TABLE' transaction failed", error); });

    // In order to test all other 'CREATE' operations, we must create the table first
    db.transaction(createTableCallback,
        function(error) { logAndTerminateTest("Write 'CREATE TABLE' transaction failed", error); });
    db.readTransaction(createStatementsCallback,
        function(error) { logAndTerminateTest("Read 'CREATE' transaction failed", error); });

    // In order to test the 'DROP' and 'other' operations, we need to first create the respective entities
    db.transaction(createStatementsCallback,
        function(error) { logAndTerminateTest("Write 'CREATE' transaction failed", error); });
    db.readTransaction(otherStatementsCallback,
        function(error) { logAndTerminateTest("Read 'other' transaction failed", error); });

    // Hack: insert an empty write transaction to guaratee that these transactions are executed sequentially
    db.transaction(function(tx) { });
    db.readTransaction(dropStatementsCallback,
        function(error) { logAndTerminateTest("Read 'DROP' transaction failed", error); },
        function() { log("Read transactions succeeded."); terminateTest(); });
}

function runTest()
{
    if (window.layoutTestController) {
        layoutTestController.dumpAsText();
        layoutTestController.waitUntilDone();
    }

    try {
        var db = openDatabase("AuthorizerTest", "1.0", "Tests the database authorizer.", 32768);
        cleanup(db);
        testReadWriteMode(db);
        testReadOnlyMode(db);
    } catch(err) {}
}
</script>
</head>
<body onload="runTest();">
This test tests the database authorizer.<br>
</body>
</html>