ADDED Tests/stress.eagle Index: Tests/stress.eagle ================================================================== --- /dev/null +++ Tests/stress.eagle @@ -0,0 +1,492 @@ +############################################################################### +# +# stress.eagle -- +# +# Written by Joe Mistachkin. +# Released to the public domain, use at your own risk! +# +############################################################################### + +package require Eagle +package require Eagle.Library +package require Eagle.Test + +runTestPrologue + +############################################################################### + +package require System.Data.SQLite.Test +runSQLiteTestPrologue + +############################################################################### + +runTest {test stress-1.1 {multithreaded stress testing} -setup { + proc expectedError { error } { + return [expr {[regexp -- {\sno such table: t1\s} $error] || \ + [regexp -- {\sdatabase is locked\s} $error]}] + } + + ############################################################################# + + proc showTest { indicator } { + tputs $::test_channel $indicator + after [expr {int(rand() * 1000)}] + } + + ############################################################################# + + proc failTest { error } { + set level [expr {[info level] - 1}] + + tputs $::test_channel [appendArgs \ + \n [info level $level] ": " $error \n] + + exit Failure; # halt all testing now. + } + + ############################################################################# + + set count(0) 1 + set count(1) 10 + + if {[info exists argv] && [llength $argv] > 0} then { + parse options [list \ + [list null MustHaveIntegerValue -1 -1 -count0 $count(0)] \ + [list null MustHaveIntegerValue -1 -1 -count1 $count(1)]] $argv + + set count(0) $options(-count0,value) + set count(1) $options(-count1,value) + } + + ############################################################################# + + tputs $test_channel [appendArgs \ + "---- workloads will repeat " $count(0) " time(s)...\n"] + + tputs $test_channel [appendArgs \ + "---- workloads will have " $count(1) " iteration(s)...\n"] + + ############################################################################# + + set compiled(12) "" + set compiled(13) "" + + ############################################################################# + + set fileName(1) "file::memory:?cache=shared" + set fileName(2) [file join [getDatabaseDirectory] stress.db] + + ############################################################################# + + setupDb $fileName(1) "" "" "" "" "" false true srcDb + setupDb $fileName(2) + + ############################################################################# + + set workload(1) [list [list srcFileName dstFileName table count] { + # + # NOTE: Workload #1, CREATE TABLE statements. + # + setupDb $dstFileName "" "" "" "" "" false + if {[catch { + for {set index 2} {$index <= $count} {incr index} { + sql execute $db [appendArgs \ + "CREATE TABLE IF NOT EXISTS t" $index "(x PRIMARY KEY, y, z);"] + showTest 1 + } + } error]} then { + if {[expectedError $error]} then { + showTest * + } else { + failTest $error + } + } + cleanupDb $dstFileName db false false + }] + + ############################################################################# + + set workload(2) [list [list srcFileName dstFileName table count] { + # + # NOTE: Workload #2, DROP TABLE statements. + # + setupDb $dstFileName "" "" "" "" "" false + if {[catch { + for {set index 2} {$index <= $count} {incr index} { + sql execute $db [appendArgs \ + "DROP TABLE IF EXISTS t" $index \;] + showTest 2 + } + } error]} then { + if {[expectedError $error]} then { + showTest * + } else { + failTest $error + } + } + cleanupDb $dstFileName db false false + }] + + ############################################################################# + + set workload(3) [list [list srcFileName dstFileName table count] { + # + # NOTE: Workload #3, "small" SELECT statements. + # + setupDb $dstFileName "" "" "" "" "" false + if {[catch { + for {set index 1} {$index <= $count} {incr index} { + sql execute -execute reader $db [appendArgs \ + "SELECT x, y FROM " $table " WHERE z = 'small';"] + showTest 3 + } + } error]} then { + if {[expectedError $error]} then { + showTest * + } else { + failTest $error + } + } + cleanupDb $dstFileName db false false + }] + + ############################################################################# + + set workload(4) [list [list srcFileName dstFileName table count] { + # + # NOTE: Workload #4, "big" SELECT statements. + # + setupDb $dstFileName "" "" "" "" "" false + if {[catch { + for {set index 1} {$index <= $count} {incr index} { + sql execute -execute reader $db [appendArgs \ + "SELECT x, y FROM " $table " WHERE z = 'big';"] + showTest 4 + } + } error]} then { + if {[expectedError $error]} then { + showTest * + } else { + failTest $error + } + } + cleanupDb $dstFileName db false false + }] + + ############################################################################# + + set workload(5) [list [list srcFileName dstFileName table count] { + # + # NOTE: Workload #5, "small" INSERT statements. + # + setupDb $dstFileName "" "" "" "" "" false + if {[catch { + for {set index 1} {$index <= $count} {incr index} { + sql execute $db [appendArgs \ + "INSERT INTO " $table "(x, y, z) VALUES('" \ + [format %lX [expr {random()}]] "', '" \ + [base64 encode -- [expr {randstr(10000)}]] \ + "', 'small');"] + showTest 5 + } + } error]} then { + if {[expectedError $error]} then { + showTest * + } else { + failTest $error + } + } + cleanupDb $dstFileName db false false + }] + + ############################################################################# + + set workload(6) [list [list srcFileName dstFileName table count] { + # + # NOTE: Workload #6, "big" INSERT statements. + # + setupDb $dstFileName "" "" "" "" "" false + if {[catch { + for {set index 1} {$index <= $count} {incr index} { + sql execute $db [appendArgs \ + "INSERT INTO " $table "(x, y, z) VALUES('" \ + [format %lX [expr {random()}]] \ + "', RANDOMBLOB(10000000), 'big');"] + showTest 6 + } + } error]} then { + if {[expectedError $error]} then { + showTest * + } else { + failTest $error + } + } + cleanupDb $dstFileName db false false + }] + + ############################################################################# + + set workload(7) [list [list srcFileName dstFileName table count] { + # + # NOTE: Workload #7, "small" UPDATE statements. + # + setupDb $dstFileName "" "" "" "" "" false + if {[catch { + for {set index 1} {$index <= $count} {incr index} { + sql execute $db [appendArgs "UPDATE " $table \ + " SET y = '" [base64 encode -- [expr {randstr(10000)}]] \ + "' WHERE x LIKE '" [format %X $index] "%' AND z = 'small';"] + showTest 7 + } + } error]} then { + if {[expectedError $error]} then { + showTest * + } else { + failTest $error + } + } + cleanupDb $dstFileName db false false + }] + + ############################################################################# + + set workload(8) [list [list srcFileName dstFileName table count] { + # + # NOTE: Workload #8, "big" UPDATE statements. + # + setupDb $dstFileName "" "" "" "" "" false + if {[catch { + for {set index 1} {$index <= $count} {incr index} { + sql execute $db [appendArgs "UPDATE " $table \ + " SET y = RANDOMBLOB(10000000) WHERE x LIKE '" \ + [format %X $index] "%' AND z = 'big';"] + showTest 8 + } + } error]} then { + if {[expectedError $error]} then { + showTest * + } else { + failTest $error + } + } + cleanupDb $dstFileName db false false + }] + + ############################################################################# + + set workload(9) [list [list srcFileName dstFileName table count] { + # + # NOTE: Workload #9, "small" DELETE statements. + # + setupDb $dstFileName "" "" "" "" "" false + if {[catch { + for {set index 1} {$index <= $count} {incr index} { + sql execute $db [appendArgs "DELETE FROM " $table \ + " WHERE x LIKE '" [format %X $index] "%' AND z = 'small';"] + showTest 9 + } + } error]} then { + if {[expectedError $error]} then { + showTest * + } else { + failTest $error + } + } + cleanupDb $dstFileName db false false + }] + + ############################################################################# + + set workload(10) [list [list srcFileName dstFileName table count] { + # + # NOTE: Workload #10, "big" DELETE statements. + # + setupDb $dstFileName "" "" "" "" "" false + if {[catch { + for {set index 1} {$index <= $count} {incr index} { + sql execute $db [appendArgs "DELETE FROM " $table \ + " WHERE x LIKE '" [format %X $index] "%' AND z = 'big';"] + showTest A + } + } error]} then { + if {[expectedError $error]} then { + showTest * + } else { + failTest $error + } + } + cleanupDb $dstFileName db false false + }] + + ############################################################################# + + set workload(11) [list [list srcFileName dstFileName table count] { + # + # NOTE: Workload #11, VACUUM statement. + # + setupDb $dstFileName "" "" "" "" "" false + if {[catch { + sql execute $db "VACUUM;" + showTest B + } error]} then { + if {[expectedError $error]} then { + showTest * + } else { + failTest $error + } + } + cleanupDb $dstFileName db false false + }] + + ############################################################################# + + set workload(12) [list [list srcFileName dstFileName table count] { + # + # NOTE: Workload #12, backup to in-memory database. + # + if {[string is integer -strict $::compiled(12)]} then { + set id $::compiled(12); # NOTE: Already compiled. + object invoke _Dynamic${id}.Test${id} BackupAndGetData + } else { + set id [object invoke Interpreter.GetActive NextId] + set code [compileCSharpWith [subst { + using System; + using System.Data.SQLite; + using System.Text; + + namespace _Dynamic${id} + { + public static class Test${id} + { + public static void BackupAndGetData() + { + using (SQLiteConnection source = new SQLiteConnection( + "FullUri=${dstFileName};")) + { + source.Open(); + using (SQLiteConnection destination = new SQLiteConnection( + "FullUri=${srcFileName};")) + { + destination.Open(); + + source.BackupDatabase( + destination, "main", "main", -1, null, 0); + } + } + } + + /////////////////////////////////////////////////////////////////// + + public static void Main() + { + // do nothing. + } + } + } + }] true true true results errors System.Data.SQLite.dll] + if {$code eq "Ok"} then { + set ::compiled(12) $id; # NOTE: Compiled OK. + object invoke _Dynamic${id}.Test${id} BackupAndGetData + } else { + error $errors + } + } + showTest C + }] + + ############################################################################# + + set workload(13) [list [list srcFileName dstFileName table count] { + # + # NOTE: Workload #13, backup from an in-memory database. + # + if {[string is integer -strict $::compiled(13)]} then { + set id $::compiled(13); # NOTE: Already compiled. + object invoke _Dynamic${id}.Test${id} BackupAndGetData + } else { + set id [object invoke Interpreter.GetActive NextId] + set code [compileCSharpWith [subst { + using System; + using System.Data.SQLite; + using System.Text; + + namespace _Dynamic${id} + { + public static class Test${id} + { + public static void BackupAndGetData() + { + using (SQLiteConnection source = new SQLiteConnection( + "FullUri=${srcFileName};")) + { + source.Open(); + using (SQLiteConnection destination = new SQLiteConnection( + "FullUri=${dstFileName};")) + { + destination.Open(); + + source.BackupDatabase( + destination, "main", "main", -1, null, 0); + } + } + } + + /////////////////////////////////////////////////////////////////// + + public static void Main() + { + // do nothing. + } + } + } + }] true true true results errors System.Data.SQLite.dll] + if {$code eq "Ok"} then { + set ::compiled(13) $id; # NOTE: Compiled OK. + object invoke _Dynamic${id}.Test${id} BackupAndGetData + } else { + error $errors + } + } + showTest D + }] +} -body { + for {set index(0) 0} {$index(0) < $count(0)} {incr index(0)} { + sql execute $db "CREATE TABLE IF NOT EXISTS t1(x PRIMARY KEY, y, z);" + + unset -nocomplain thread + + foreach index(1) [array names workload] { + set thread($index(1)) [object create -alias System.Threading.Thread \ + [list apply $workload($index(1)) $fileName(1) $fileName(2) t1 \ + $count(1)]] + } + + foreach index(1) [array names thread] { + $thread($index(1)) Start + } + + foreach index(1) [array names thread] { + $thread($index(1)) Join + } + + unset -nocomplain thread + } + + tputs $test_channel \n +} -cleanup { + rename failTest "" + rename showTest "" + rename expectedError "" + + cleanupDb $fileName(2) + cleanupDb $fileName(1) srcDb + + unset -nocomplain thread index workload srcDb db fileName compiled options \ + count +} -constraints \ +{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -result {}} + +############################################################################### + +runSQLiteTestEpilogue +runTestEpilogue