1 function terminateTest() 2 { 3 if (window.layoutTestController) 4 layoutTestController.notifyDone(); 5 } 6 7 function logAndTerminateTest(message, error) 8 { 9 log(message + ": " + error.message); 10 terminateTest(); 11 } 12 13 function cleanup(db) 14 { 15 db.transaction(function(tx) { 16 tx.executeSql("DROP TABLE IF EXISTS Test;"); 17 tx.executeSql("DROP INDEX IF EXISTS TestIndex;"); 18 tx.executeSql("DROP VIEW IF EXISTS TestView;"); 19 tx.executeSql("DROP TRIGGER IF EXISTS TestTrigger;"); 20 }, function(error) { logAndTerminateTest("Cleanup failed", error); }); 21 } 22 23 function statementSuccessCallback(statementType) 24 { 25 log(statementType + " statement succeeded."); 26 } 27 28 function statementErrorCallback(statementType, error) 29 { 30 log(statementType + " statement failed: " + error.message); 31 return false; 32 } 33 34 function executeStatement(tx, statement, operation) 35 { 36 tx.executeSql(statement, [], 37 function(result) { statementSuccessCallback(operation); }, 38 function(tx, error) { return statementErrorCallback(operation, error); }); 39 } 40 41 function createTableCallback(tx) 42 { 43 executeStatement(tx, "CREATE TABLE Test (Foo int);", "SQLITE_CREATE_TABLE"); 44 } 45 46 function createStatementsCallback(tx) 47 { 48 executeStatement(tx, "CREATE INDEX TestIndex ON Test (Foo);", "SQLITE_CREATE_INDEX"); 49 50 // Even though the following query should trigger a SQLITE_CREATE_TEMP_INDEX operation 51 // (according to http://www.sqlite.org/tempfiles.html), it doesn't, and I'm not aware 52 // of any other way to trigger this operation. So we'll skip it for now. 53 //executeStatement(tx, "SELECT * FROM Test WHERE Foo IN (1, 2, 3);", "SQLITE_CREATE_TEMP_INDEX"); 54 55 executeStatement(tx, "CREATE TEMP TABLE TestTempTable (Foo int);", "SQLITE_CREATE_TEMP_TABLE"); 56 executeStatement(tx, "CREATE TEMP TRIGGER TestTempTrigger INSERT ON Test BEGIN SELECT COUNT(*) FROM Test; END;", "SQLITE_CREATE_TEMP_TRIGGER"); 57 executeStatement(tx, "CREATE TEMP VIEW TestTempView AS SELECT COUNT(*) FROM Test;", "SQLITE_CREATE_TEMP_VIEW"); 58 executeStatement(tx, "CREATE TRIGGER TestTrigger INSERT ON Test BEGIN SELECT COUNT(*) FROM Test; END;", "SQLITE_CREATE_TRIGGER"); 59 executeStatement(tx, "CREATE VIEW TestView AS SELECT COUNT(*) FROM Test;", "SQLITE_CREATE_VIEW"); 60 executeStatement(tx, "CREATE VIRTUAL TABLE TestVirtualTable USING MissingModule;", "SQLITE_CREATE_VTABLE"); 61 } 62 63 function otherStatementsCallback(tx) 64 { 65 executeStatement(tx, "SELECT COUNT(*) FROM Test;", "SQLITE_READ"); 66 executeStatement(tx, "SELECT COUNT(*) FROM Test;", "SQLITE_SELECT"); 67 executeStatement(tx, "DELETE FROM Test;", "SQLITE_DELETE"); 68 executeStatement(tx, "INSERT INTO Test VALUES (1);", "SQLITE_INSERT"); 69 executeStatement(tx, "UPDATE Test SET Foo = 2 WHERE Foo = 1;", "SQLITE_UPDATE"); 70 executeStatement(tx, "PRAGMA cache_size;", "SQLITE_PRAGMA"); 71 72 executeStatement(tx, "ALTER TABLE Test RENAME TO TestTable;", "SQLITE_ALTER_TABLE"); 73 // Rename the table back to its original name 74 executeStatement(tx, "ALTER TABLE TestTable RENAME To Test;", "SQLITE_ALTER_TABLE"); 75 76 executeStatement(tx, "BEGIN TRANSACTION;", "SQLITE_TRANSACTION"); 77 executeStatement(tx, "ATTACH main AS TestMain;", "SQLITE_ATTACH"); 78 executeStatement(tx, "DETACH TestMain;", "SQLITE_DETACH"); 79 executeStatement(tx, "REINDEX;", "SQLITE_REINDEX"); 80 executeStatement(tx, "ANALYZE;", "SQLITE_ANALYZE"); 81 82 // SQLITE_FUNCTION: allowed write mode 83 // There is no SQL/Javascript API to add user-defined functions to SQLite, 84 // so we cannot test this operation 85 } 86 87 function dropStatementsCallback(tx) 88 { 89 executeStatement(tx, "DROP INDEX TestIndex;", "SQLITE_DROP_INDEX"); 90 91 // SQLITE_DROP_TEMP_INDEX: allowed in write mode 92 // Not sure how to test this: temp indexes are automatically dropped when 93 // the database is closed, but HTML5 doesn't specify a closeDatabase() call. 94 95 executeStatement(tx, "DROP TABLE TestTempTable;", "SQLITE_DROP_TEMP_TABLE"); 96 executeStatement(tx, "DROP TRIGGER TestTempTrigger;", "SQLITE_DROP_TEMP_TRIGGER"); 97 executeStatement(tx, "DROP VIEW TestTempView;", "SQLITE_DROP_TEMP_VIEW"); 98 executeStatement(tx, "DROP TRIGGER TestTrigger;", "SQLITE_DROP_TRIGGER"); 99 executeStatement(tx, "DROP VIEW TestView;", "SQLITE_DROP_VIEW"); 100 101 // SQLITE_DROP_VTABLE: allowed in write mode 102 // Not sure how to test this: we cannot create a virtual table because we do not 103 // have SQL/Javascript APIs to register a module that implements a virtual table. 104 // Therefore, trying to drop a virtual table will always fail (no such table) 105 // before even getting to the authorizer. 106 107 executeStatement(tx, "DROP TABLE Test;", "SQLITE_DROP_TABLE"); 108 } 109 110 function testReadWriteMode(db) 111 { 112 db.transaction(function(tx) { 113 createTableCallback(tx); 114 createStatementsCallback(tx); 115 otherStatementsCallback(tx); 116 dropStatementsCallback(tx); 117 }, 118 function(error) { logAndTerminateTest("Write transaction failed", error); }, 119 function() { log("Write transaction succeeded."); }); 120 } 121 122 function testReadOnlyMode(db) 123 { 124 // Test the 'CREATE TABLE' operation; it should be disallowed 125 db.readTransaction(createTableCallback, 126 function(error) { logAndTerminateTest("Read 'CREATE TABLE' transaction failed", error); }); 127 128 // In order to test all other 'CREATE' operations, we must create the table first 129 db.transaction(createTableCallback, 130 function(error) { logAndTerminateTest("Write 'CREATE TABLE' transaction failed", error); }); 131 db.readTransaction(createStatementsCallback, 132 function(error) { logAndTerminateTest("Read 'CREATE' transaction failed", error); }); 133 134 // In order to test the 'DROP' and 'other' operations, we need to first create the respective entities 135 db.transaction(createStatementsCallback, 136 function(error) { logAndTerminateTest("Write 'CREATE' transaction failed", error); }); 137 db.readTransaction(otherStatementsCallback, 138 function(error) { logAndTerminateTest("Read 'other' transaction failed", error); }); 139 140 // Hack: insert an empty write transaction to guaratee that these transactions are executed sequentially 141 db.transaction(function(tx) { }); 142 db.readTransaction(dropStatementsCallback, 143 function(error) { logAndTerminateTest("Read 'DROP' transaction failed", error); }, 144 function() { log("Read transactions succeeded."); terminateTest(); }); 145 } 146 147 function runTest() 148 { 149 var db = openDatabaseWithSuffix("AuthorizerTest", "1.0", "Tests the database authorizer.", 32768); 150 cleanup(db); 151 testReadWriteMode(db); 152 testReadOnlyMode(db); 153 } 154