Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Improve test coverage of ota code a bit. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | ota-update |
Files: | files | file ages | folders |
SHA1: |
a438fa6c9ad2fb1d78ac747172d07455 |
User & Date: | dan 2015-02-17 20:49:42.756 |
Context
2015-02-18
| ||
17:40 | Fix a problem with OTA updates in the presence of database readers. (check-in: 144bb29ffc user: dan tags: ota-update) | |
2015-02-17
| ||
20:49 | Improve test coverage of ota code a bit. (check-in: a438fa6c9a user: dan tags: ota-update) | |
2015-02-16
| ||
21:13 | Add extra tests and fixes for ota. (check-in: e0b7151962 user: dan tags: ota-update) | |
Changes
Changes to ext/ota/otafault.test.
︙ | ︙ | |||
13 14 15 16 17 18 19 | if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl source $testdir/malloc_common.tcl set ::testprefix otafault | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < < | | | | | < < < < < < < | | | | | | | | | | 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 176 177 178 179 180 181 182 183 184 185 186 187 188 | if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl source $testdir/malloc_common.tcl set ::testprefix otafault proc copy_if_exists {src target} { if {[file exists $src]} { forcecopy $src $target } else { forcedelete $target } } foreach {tn2 setup sql expect} { 1 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); CREATE INDEX t1cb ON t1(c, b); INSERT INTO t1 VALUES(1, 1, 1); INSERT INTO t1 VALUES(2, 2, 2); INSERT INTO t1 VALUES(3, 3, 3); CREATE TABLE ota.data_t1(a, b, c, ota_control); INSERT INTO data_t1 VALUES(2, NULL, NULL, 1); INSERT INTO data_t1 VALUES(3, 'three', NULL, '.x.'); INSERT INTO data_t1 VALUES(4, 4, 4, 0); } {SELECT * FROM t1} {1 1 1 3 three 3 4 4 4} 2 { CREATE TABLE t2(a PRIMARY KEY, b, c) WITHOUT ROWID; CREATE INDEX t2cb ON t2(c, b); INSERT INTO t2 VALUES('a', 'a', 'a'); INSERT INTO t2 VALUES('b', 'b', 'b'); INSERT INTO t2 VALUES('c', 'c', 'c'); CREATE TABLE ota.data_t2(a, b, c, ota_control); INSERT INTO data_t2 VALUES('b', NULL, NULL, 1); INSERT INTO data_t2 VALUES('c', 'see', NULL, '.x.'); INSERT INTO data_t2 VALUES('d', 'd', 'd', 0); } {SELECT * FROM t2} {a a a c see c d d d} 3 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); CREATE TABLE t2(a PRIMARY KEY, b, c) WITHOUT ROWID; CREATE INDEX t1cb ON t1(c, b); CREATE INDEX t2cb ON t2(c, b); CREATE TABLE ota.data_t1(a, b, c, ota_control); CREATE TABLE ota.data_t2(a, b, c, ota_control); INSERT INTO data_t1 VALUES(1, 2, 3, 0); INSERT INTO data_t2 VALUES(4, 5, 6, 0); } {SELECT * FROM t1 UNION ALL SELECT * FROM t2} {1 2 3 4 5 6} } { catch {db close} forcedelete ota.db test.db sqlite3 db test.db execsql { PRAGMA encoding = utf16; ATTACH 'ota.db' AS ota; } execsql $setup db close forcecopy test.db test.db.bak forcecopy ota.db ota.db.bak foreach {tn f reslist} { 1 oom-tra* { {0 SQLITE_DONE} {1 {SQLITE_NOMEM - out of memory}} {1 SQLITE_NOMEM} {1 SQLITE_IOERR_NOMEM} {1 {SQLITE_NOMEM - unable to open a temporary database file for storing temporary tables}} } 2 ioerr-* { {0 SQLITE_DONE} {1 {SQLITE_IOERR - disk I/O error}} {1 SQLITE_IOERR} {1 SQLITE_IOERR_WRITE} {1 SQLITE_IOERR_READ} {1 SQLITE_IOERR_FSYNC} {1 {SQLITE_ERROR - SQL logic error or missing database}} {1 {SQLITE_ERROR - unable to open database: ota.db}} {1 {SQLITE_IOERR - unable to open database: ota.db}} } } { catch {db close} sqlite3_shutdown set lookaside_config [sqlite3_config_lookaside 0 0] sqlite3_initialize autoinstall_test_functions do_faultsim_test 2.$tn2 -faults $::f -prep { catch { db close } forcedelete test.db-journal test.db-wal ota.db-journal ota.db-wal forcecopy test.db.bak test.db forcecopy ota.db.bak ota.db } -body { sqlite3ota ota test.db ota.db while {[ota step]=="SQLITE_OK"} {} ota close } -test { faultsim_test_result {*}$::reslist if {$testrc==0} { sqlite3 db test.db faultsim_integrity_check set res [db eval $::sql] if {$res != [list {*}$::expect]} { puts "" puts "res: $res" puts "exp: $expect" error "data not as expected!" } } } catch {db close} sqlite3_shutdown sqlite3_config_lookaside {*}$lookaside_config sqlite3_initialize autoinstall_test_functions } for {set iStep 0} {$iStep<=21} {incr iStep} { forcedelete test.db-journal test.db-wal ota.db-journal ota.db-wal copy_if_exists test.db.bak test.db copy_if_exists ota.db.bak ota.db sqlite3ota ota test.db ota.db for {set x 0} {$x < $::iStep} {incr x} { ota step } ota close copy_if_exists test.db test.db.bak.2 copy_if_exists test.db-wal test.db.bak.2-wal copy_if_exists test.db-oal test.db.bak.2-oal copy_if_exists ota.db ota.db.bak.2 do_faultsim_test 3.$tn.$iStep -faults $::f -prep { catch { db close } forcedelete test.db-journal test.db-wal ota.db-journal ota.db-wal copy_if_exists test.db.bak.2 test.db copy_if_exists test.db.bak.2-wal test.db-wal copy_if_exists test.db.bak.2-oal test.db-oal copy_if_exists ota.db.bak.2 ota.db } -body { sqlite3ota ota test.db ota.db while {[ota step] == "SQLITE_OK"} {} ota close } -test { faultsim_test_result {*}$::reslist if {$testrc==0} { sqlite3 db test.db faultsim_integrity_check set res [db eval $::sql] if {$res != [list {*}$::expect]} { puts "" puts "res: $res" puts "exp: $expected" error "data not as expected!" } } } } } finish_test |
Changes to ext/ota/sqlite3ota.c.
︙ | ︙ | |||
569 570 571 572 573 574 575 | ** } ** }else if( "PRAGMA table_info()" lists one or more "pk" columns ){ ** return OTA_PK_IPK ** }else{ ** return OTA_PK_NONE ** } */ | | | > > > > > > | < < < > > > | | | < < < < < > | > | | | | | < < | < | | | > | > | | < < < < < < < > | < < < < | | | | | | > > > > | > | < < | < | < | | | > | < > > | | > > | 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 | ** } ** }else if( "PRAGMA table_info()" lists one or more "pk" columns ){ ** return OTA_PK_IPK ** }else{ ** return OTA_PK_NONE ** } */ static void otaTableType( sqlite3ota *p, const char *zTab, int *peType, int *piPk ){ /* ** 0) SELECT count(*) FROM sqlite_master where name=%Q AND IsVirtual(%Q) ** 1) PRAGMA index_list = ? ** 2) SELECT count(*) FROM sqlite_master where name=%Q ** 3) PRAGMA table_info = ? */ sqlite3_stmt *aStmt[4] = {0, 0, 0, 0}; *peType = OTA_PK_NOTABLE; *piPk = 0; assert( p->rc==SQLITE_OK ); p->rc = prepareFreeAndCollectError(p->db, &aStmt[0], &p->zErrmsg, sqlite3_mprintf( "SELECT (sql LIKE 'create virtual%%')" " FROM sqlite_master" " WHERE name=%Q", zTab )); if( p->rc!=SQLITE_OK || sqlite3_step(aStmt[0])!=SQLITE_ROW ){ /* Either an error, or no such table. */ goto otaTableType_end; } if( sqlite3_column_int(aStmt[0], 0) ){ *peType = OTA_PK_VTAB; /* virtual table */ goto otaTableType_end; } p->rc = prepareFreeAndCollectError(p->db, &aStmt[1], &p->zErrmsg, sqlite3_mprintf("PRAGMA index_list=%Q",zTab) ); if( p->rc ) goto otaTableType_end; while( sqlite3_step(aStmt[1])==SQLITE_ROW ){ const u8 *zOrig = sqlite3_column_text(aStmt[1], 3); const u8 *zIdx = sqlite3_column_text(aStmt[1], 1); if( zOrig && zIdx && zOrig[0]=='p' ){ p->rc = prepareFreeAndCollectError(p->db, &aStmt[2], &p->zErrmsg, sqlite3_mprintf( "SELECT rootpage FROM sqlite_master WHERE name = %Q", zIdx )); if( p->rc==SQLITE_OK ){ if( sqlite3_step(aStmt[2])==SQLITE_ROW ){ *piPk = sqlite3_column_int(aStmt[2], 0); *peType = OTA_PK_EXTERNAL; }else{ *peType = OTA_PK_WITHOUT_ROWID; } } goto otaTableType_end; } } p->rc = prepareFreeAndCollectError(p->db, &aStmt[3], &p->zErrmsg, sqlite3_mprintf("PRAGMA table_info=%Q",zTab) ); if( p->rc==SQLITE_OK ){ while( sqlite3_step(aStmt[3])==SQLITE_ROW ){ if( sqlite3_column_int(aStmt[3],5)>0 ){ *peType = OTA_PK_IPK; /* explicit IPK column */ goto otaTableType_end; } } *peType = OTA_PK_NONE; } otaTableType_end: { int i; for(i=0; i<sizeof(aStmt)/sizeof(aStmt[0]); i++){ int rc2 = sqlite3_finalize(aStmt[i]); if( p->rc==SQLITE_OK ) p->rc = rc2; } } } /* ** If they are not already populated, populate the pIter->azTblCol[], ** pIter->abTblPk[], pIter->nTblCol and pIter->bRowid variables according to ** the table (not index) that the iterator currently points to. |
︙ | ︙ | |||
672 673 674 675 676 677 678 | int i; /* for() loop iterator variable */ int rc2; /* sqlite3_finalize() return value */ int bOtaRowid = 0; /* If input table has column "ota_rowid" */ int iOrder = 0; /* Figure out the type of table this step will deal with. */ assert( pIter->eType==0 ); | | | 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 | int i; /* for() loop iterator variable */ int rc2; /* sqlite3_finalize() return value */ int bOtaRowid = 0; /* If input table has column "ota_rowid" */ int iOrder = 0; /* Figure out the type of table this step will deal with. */ assert( pIter->eType==0 ); otaTableType(p, pIter->zTbl, &pIter->eType, &pIter->iPkTnum); if( p->rc ) return p->rc; assert( pIter->eType==OTA_PK_NONE || pIter->eType==OTA_PK_IPK || pIter->eType==OTA_PK_EXTERNAL || pIter->eType==OTA_PK_WITHOUT_ROWID || pIter->eType==OTA_PK_VTAB ); |
︙ | ︙ | |||
1099 1100 1101 1102 1103 1104 1105 | } break; } } rc = sqlite3_finalize(pXList); if( p->rc==SQLITE_OK ) p->rc = rc; | | > > > > > > > > > > > > > > > > > > > | 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 | } break; } } rc = sqlite3_finalize(pXList); if( p->rc==SQLITE_OK ) p->rc = rc; while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){ if( sqlite3_column_int(pXInfo, 5) ){ /* int iCid = sqlite3_column_int(pXInfo, 0); */ const char *zCol = (const char*)sqlite3_column_text(pXInfo, 2); const char *zDesc = sqlite3_column_int(pXInfo, 3) ? " DESC" : ""; z = otaMPrintf(p, "%z%s\"%w\"%s", z, zSep, zCol, zDesc); zSep = ", "; } } z = otaMPrintf(p, "%z)", z); rc = sqlite3_finalize(pXInfo); if( p->rc==SQLITE_OK ) p->rc = rc; } return z; } /* ** This function creates the second imposter table used when writing to ** a table b-tree where the table has an external primary key. If the ** iterator passed as the second argument does not currently point to ** a table (not index) with an external primary key, this function is a ** no-op. ** ** Assuming the iterator does point to a table with an external PK, this ** function creates a WITHOUT ROWID imposter table named "ota_imposter2" ** used to access that PK index. For example, if the target table is ** declared as follows: ** ** CREATE TABLE t1(a, b TEXT, c REAL, PRIMARY KEY(b, c)); ** ** then the imposter table schema is: ** ** CREATE TABLE ota_imposter2(c1 TEXT, c2 REAL, id INTEGER) WITHOUT ROWID; ** */ static void otaCreateImposterTable2(sqlite3ota *p, OtaObjIter *pIter){ if( p->rc==SQLITE_OK && pIter->eType==OTA_PK_EXTERNAL ){ int tnum = pIter->iPkTnum; /* Root page of PK index */ sqlite3_stmt *pQuery = 0; /* SELECT name ... WHERE rootpage = $tnum */ const char *zIdx = 0; /* Name of PK index */ sqlite3_stmt *pXInfo = 0; /* PRAGMA main.index_xinfo = $zIdx */ int rc; |
︙ | ︙ |