# 2013 February 08
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# The focus of this file is testing the LSM library. 
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lsm_common.tcl
set testprefix lsm5
db close

# Create a new database with file name $file.
#
proc create_abc_db {file} {
  forcedelete $file
  lsm_open db $file {block_size 256 mmap 0}
  db write a alpha
  db write b bravo
  db write c charlie
  db close
}

proc create_abc_log {file} {
  forcedelete $file ${file}-2
  lsm_open db ${file}-2 {mmap 0}
  db write a alpha
  db write b bravo
  db write c charlie
  file copy ${file}-2 $file
  file copy ${file}-2-log $file-log
  db close
}

#-------------------------------------------------------------------------
# When the database system is shut down (i.e. when the last connection
# disconnects), an attempt is made to truncate the database file to the
# minimum number of blocks required.
# 
# This test case checks that this process does not actually cause the
# database to grow.
# 
do_test 1.1 {
  lsm_open db test.db {mmap 0}
} {db}
do_test 1.2 {
  db write 1 one
  db write 2 two
  db close
} {}
do_test 1.3 {
  expr [file size test.db] <= (256*1024)
} 1

#-------------------------------------------------------------------------
# Test that if an attempt is made to open a read-write connection to a 
# non-live database that the client does not have permission to write to is
# attempted an error is reported. In order to open a read-write connection 
# to a database, the client requires:
#
#   * read-write access to the db file,
#   * read-write access to the log file,
#   * for multi-process mode, read-write access to the shm file.
#
# In the above, "read-write access" includes the ability to create the db,
# log or shm file if it does not exist.
#
# These tests verify that the lsm_open() command returns LSM_IOERR. At some
# point in the future this will be improved. Likely when sqlite4 level tests 
# for opening read-only databases are added.
# 
foreach {tn filename setup} {

  1 test.dir/test.db {
    # Create a directory "test.dir".
    forcedelete test.dir
    file mkdir test.dir

    # Create a database within test.dir
    create_abc_db test.dir/test.db
  
    # Now make the db and its directory read-only.
    file attr test.dir/test.db -perm r--r--r--
    file attr test.dir -perm r-xr-xr-x
  }

  2 test.db {
    # Create a database test.db and set its permissions to read-only
    create_abc_db test.db
    file attr test.db -perm r--r--r--
  }

  3 test.dir/test.db {
    # Create a directory "test.dir".
    forcedelete test.dir
    file mkdir test.dir

    # Create a database within test.dir
    create_abc_db test.dir/test.db
  
    # Now make test.dir read-only.
    file attr test.dir -perm r-xr-xr-x
  }

} {
  do_test 2.$tn.1 {
    eval $setup
    set rc [catch {lsm_open db $filename} msg]
    list $rc $msg
  } {1 {error in lsm_open() - 10}}

  do_test 2.$tn.2 {
    eval $setup
    lsm_open db $filename {readonly 1}
    set res [list [db_fetch db a] [db_fetch db b] [db_fetch db c]]
    db close
    set res
  } {alpha bravo charlie}
}

#-------------------------------------------------------------------------
# Try having a read-only connection connect to a non-live system where the
# log file contains content. In this scenario the read-only client must 
# read the contents from the log file at the start of each read-transaction. 
#
do_test 3.1 {
  create_abc_log test.db
  list [file size test.db] [file size test.db-log]
} {0 56}
do_test 3.2 {
  lsm_open db $filename {readonly 1}
  set res [list [db_fetch db a] [db_fetch db b] [db_fetch db c]]
  db close
  set res
} {alpha bravo charlie}
do_test 3.3 {
  list [file size test.db] [file size test.db-log]
} {0 56}

# Now make the same db live and check the read-only connection can still
# read it.
do_test 3.4 { file exists test.db-shm } 0
do_test 3.5 { 
  lsm_open db_rw test.db
  file exists test.db-shm
} 1
do_test 3.6 {
  lsm_open db test.db {readonly 1}
  list [db_fetch db a] [db_fetch db b] [db_fetch db c]
} {alpha bravo charlie}

# Close the read-write connection. This should cause a checkpoint and delete
# the log file, even though the system remains live.
do_test 3.7 { 
  db_rw close
  list [file exists test.db-log] [file exists test.db-shm]
} {0 1}

# Now close the read-only connection. The system is now non-live, but the 
# *-shm remains in the file-system (the readonly connection cannot unlink it).
do_test 3.8 { 
  db close
  list [file exists test.db-log] [file exists test.db-shm]
} {0 1}

#-------------------------------------------------------------------------
#
do_test 4.1 {
  create_abc_log test.db
  list [file size test.db] [file size test.db-log]
} {0 56}

do_test 4.2 {
  lsm_open db test.db {readonly 1}
  db csr_open T
  list [db_fetch db a] [db_fetch db b] [db_fetch db c]
} {alpha bravo charlie}

do_test 4.3 { 
  lsm_open db_rw test.db {block_size 64}
  db_rw write b BRAVO
  db_rw close
  list [file size test.db] [file size test.db-log]
} {65536 74}

do_test 4.4 {
  list [db_fetch db a] [db_fetch db b] [db_fetch db c]
} {alpha bravo charlie}

do_test 4.5 {
  T close
  list [db_fetch db a] [db_fetch db b] [db_fetch db c]
} {alpha BRAVO charlie}

finish_test

