add automated test script, along with options to automate filesystem creation

git-svn-id: http://encfs.googlecode.com/svn/trunk@53 db9cf616-1c43-0410-9cb8-a902689de0d6
This commit is contained in:
Valient Gough 2009-12-07 19:15:23 +00:00
parent 39bae7bbf5
commit 9ba581ad00
7 changed files with 283 additions and 19 deletions

View File

@ -5,6 +5,7 @@ Thu Nov 26 2009 Valient Gough <vgough@pobox.com>
* don't enable valgrind support unless explicitly requested.
Fix for issue 35.
* fix INSTALL instructions. issue 47
* add --standard and --paranoia options to automate creation
Sun Nov 22 2009 Valient Gough <vgough@pobox.com>
* use lutimes instead of utimes, so that symlinks can have time modified

View File

@ -934,7 +934,8 @@ bool selectZeroBlockPassThrough()
RootPtr createV6Config( EncFS_Context *ctx, const std::string &rootDir,
bool enableIdleTracking, bool forceDecode,
const std::string &passwordProgram,
bool useStdin, bool reverseEncryption )
bool useStdin, bool reverseEncryption,
ConfigMode configMode)
{
RootPtr rootInfo;
@ -943,16 +944,19 @@ RootPtr createV6Config( EncFS_Context *ctx, const std::string &rootDir,
// xgroup(setup)
cout << _("Creating new encrypted volume.") << endl;
// xgroup(setup)
cout << _("Please choose from one of the following options:\n"
" enter \"x\" for expert configuration mode,\n"
" enter \"p\" for pre-configured paranoia mode,\n"
" anything else, or an empty line will select standard mode.\n"
"?> ");
char answer[10] = {0};
fgets( answer, sizeof(answer), stdin );
cout << "\n";
if(configMode == Config_Prompt)
{
// xgroup(setup)
cout << _("Please choose from one of the following options:\n"
" enter \"x\" for expert configuration mode,\n"
" enter \"p\" for pre-configured paranoia mode,\n"
" anything else, or an empty line will select standard mode.\n"
"?> ");
fgets( answer, sizeof(answer), stdin );
cout << "\n";
}
int keySize = 0;
int blockSize = 0;
@ -975,7 +979,7 @@ RootPtr createV6Config( EncFS_Context *ctx, const std::string &rootDir,
blockMACRandBytes = 0;
}
if(answer[0] == 'p')
if(configMode == Config_Paranoia || answer[0] == 'p')
{
if (reverseEncryption)
{
@ -1000,8 +1004,7 @@ RootPtr createV6Config( EncFS_Context *ctx, const std::string &rootDir,
chainedIV = true;
externalIV = true;
desiredKDFDuration = ParanoiaKDFDuration;
} else
if(answer[0] != 'x')
} else if(configMode == Config_Standard || answer[0] != 'x')
{
// xgroup(setup)
cout << _("Standard configuration selected.") << "\n";
@ -1565,7 +1568,7 @@ RootPtr initFS( EncFS_Context *ctx, const shared_ptr<EncFS_Opts> &opts )
}
}
// first, instanciate the cipher.
// first, instanciate the cipher.
shared_ptr<Cipher> cipher = config.getCipher();
if(!cipher)
{
@ -1649,7 +1652,7 @@ RootPtr initFS( EncFS_Context *ctx, const shared_ptr<EncFS_Opts> &opts )
// creating a new encrypted filesystem
rootInfo = createV6Config( ctx, opts->rootDir, opts->idleTracking,
opts->forceDecode, opts->passwordProgram, opts->useStdin,
opts->reverseEncryption );
opts->reverseEncryption, opts->configMode );
}
}

View File

@ -142,6 +142,12 @@ ConfigType readConfig( const std::string &rootDir, EncFSConfig *config );
bool saveConfig( ConfigType type, const std::string &rootdir,
EncFSConfig *config );
enum ConfigMode
{
Config_Prompt,
Config_Standard,
Config_Paranoia
};
struct EncFS_Opts
{
@ -159,6 +165,9 @@ struct EncFS_Opts
bool ownerCreate; // set owner of new files to caller
bool reverseEncryption; // Reverse encryption
ConfigMode configMode;
EncFS_Opts()
{
createIfNotFound = true;
@ -169,6 +178,7 @@ struct EncFS_Opts
useStdin = false;
ownerCreate = false;
reverseEncryption = false;
configMode = Config_Prompt;
}
};
@ -180,7 +190,7 @@ RootPtr createV6Config( EncFS_Context *ctx, const std::string &rootDir,
bool enableIdleTracking,
bool forceDecode,
const std::string &passwordProgram, bool reverseEncryption,
bool allowHoles );
bool allowHoles, ConfigMode mode );
void showFSInfo( const EncFSConfig &config );

View File

@ -144,3 +144,9 @@ encfs-man.html: encfs.pod
@POD2HTML@ encfs.pod > $@
endif
tests:
perl -MTest::Harness -e '$$Test::Harness::verbose=0; runtests @ARGV;' *.t
tests-verbose:
perl -MTest::Harness -e '$$Test::Harness::verbose=1; runtests @ARGV;' *.t

View File

@ -19,7 +19,8 @@ B<encfs> [B<--version>] [B<-s>] [B<-f>] [B<-v>|B<--verbose>]
[B<-i MINUTES>|B<--idle=MINUTES>] [B<--extpass=program>]
[B<-S>|B<--stdinpass>] [B<--anykey>] [B<--forcedecode>]
[B<-d>|B<--fuse-debug>] [B<--public>] [B<--no-default-flags>]
[B<--ondemand>] [B<--reverse>] [B<-o FUSE_OPTION>]
[B<--ondemand>] [B<--reverse>] [B<--standard>]
[B<-o FUSE_OPTION>]
I<rootdir> I<mountPoint>
[B<--> [I<Fuse Mount Options>]]
@ -138,6 +139,15 @@ Now /tmp/plain-view contains the same data as /home/me
Note that B<--reverse> mode only works with limited configuration options, so
many settings may be disabled when used.
=item B<--standard>
If creating a new filesystem, this automatically selects standard configuration
options, to help with automatic filesystem creation. This is the set of
options that should be used unless you know what you're doing and have read the
documentation.
When not creating a filesystem, this flag does nothing.
=item B<-o FUSE_ARG>
Pass through B<FUSE> args to the underlying library. This makes it easy to

View File

@ -226,6 +226,8 @@ bool processArgs(int argc, char *argv[], const shared_ptr<EncFS_Args> &out)
{"verbose", 0, 0, 'v'}, // verbose mode
{"version", 0, 0, 'V'}, //version
{"reverse", 0, 0, 'r'}, // reverse encryption
{"standard", 0, 0, '1'}, // standard configuration
{"paranoia", 0, 0, '2'}, // standard configuration
{0,0,0,0}
};
@ -249,6 +251,12 @@ bool processArgs(int argc, char *argv[], const shared_ptr<EncFS_Args> &out)
switch( res )
{
case '1':
out->opts->configMode = Config_Standard;
break;
case '2':
out->opts->configMode = Config_Paranoia;
break;
case 's':
out->isThreaded = false;
break;
@ -523,7 +531,7 @@ int main(int argc, char *argv[])
encfs_oper.getattr = encfs_getattr;
encfs_oper.readlink = encfs_readlink;
encfs_oper.getdir = encfs_getdir;
encfs_oper.getdir = encfs_getdir; // deprecated for readdir
encfs_oper.mknod = encfs_mknod;
encfs_oper.mkdir = encfs_mkdir;
encfs_oper.unlink = encfs_unlink;
@ -534,7 +542,7 @@ int main(int argc, char *argv[])
encfs_oper.chmod = encfs_chmod;
encfs_oper.chown = encfs_chown;
encfs_oper.truncate = encfs_truncate;
encfs_oper.utime = encfs_utime;
encfs_oper.utime = encfs_utime; // deprecated for utimens
encfs_oper.open = encfs_open;
encfs_oper.read = encfs_read;
encfs_oper.write = encfs_write;
@ -558,9 +566,22 @@ int main(int argc, char *argv[])
//encfs_oper.create = encfs_create;
encfs_oper.ftruncate = encfs_ftruncate;
encfs_oper.fgetattr = encfs_fgetattr;
//encfs_oper.lock = encfs_lock;
encfs_oper.utimens = encfs_utimens;
//encfs_oper.bmap = encfs_bmap;
#if (__FreeBSD__ >= 10)
// encfs_oper.setvolname
// encfs_oper.exchange
// encfs_oper.getxtimes
// encfs_oper.setbkuptime
// encfs_oper.setchgtime
// encfs_oper.setcrtime
// encfs_oper.chflags
// encfs_oper.setattr_x
// encfs_oper.fsetattr_x
#endif
openssl_init( encfsArgs->isThreaded );
// context is not a smart pointer because it will live for the life of

213
encfs/tests.t Normal file
View File

@ -0,0 +1,213 @@
#!/usr/bin/perl -w
use Test::More qw( no_plan );
use File::Path;
use IO::Handle;
use Digest::MD5;
my $tempDir = $ENV{'TMPDIR'} || "/tmp";
my $raw = "$tempDir/crypt-raw-$$";
my $crypt = "$tempDir/crypt-$$";
# test filesystem in standard config mode
&runTests('standard');
# test in paranoia mode
&runTests('paranoia');
sub runTests
{
my $mode = shift;
my $hardlinks = 1;
if($mode eq 'standard')
{
&mount("--standard");
} elsif($mode eq 'paranoia')
{
&mount("--paranoia");
$hardlinks = 0; # no hardlinks in paranoia mode
} else
{
die "invalid test mode";
}
# tests..
&fileCreation;
&links($hardlinks);
&truncate;
&renames;
&cleanup;
}
sub renames
{
ok( open(F, ">$crypt/orig-name") && close F, "create file for rename test");
ok( -f "$crypt/orig-name", "file exists");
ok( rename("$crypt/orig-name", "$crypt/2nd-name"), "rename");
ok( ! -f "$crypt/orig-name", "file exists");
ok( -f "$crypt/2nd-name", "file exists");
# rename directory with contents
ok( mkpath("$crypt/orig-dir/foo"), "mkdir for rename test");
ok( open(F, ">$crypt/orig-dir/foo/bar") && close F, "make file");
ok( rename("$crypt/orig-dir", "$crypt/new-dir"), "rename dir");
ok( -f "$crypt/new-dir/foo/bar", "dir rename contents");
# TODO: rename failure? (check undo works)
# check time stamps of files on rename
my $mtime = (stat "$crypt/2nd-name")[9];
# change time to 60 seconds earlier
my $olderTime = $mtime - 60;
ok( utime($olderTime, $olderTime, "$crypt/2nd-name"), "change time");
ok( rename("$crypt/2nd-name", "$crypt/3rd-name"), "rename");
is( (stat "$crypt/3rd-name")[9], $olderTime, "time unchanged by rename");
}
sub truncate
{
# write to file, then truncate it
ok( open(OUT, "+> $crypt/trunc"), "create truncate-test file");
autoflush OUT 1;
print OUT "12345678901234567890";
is( -s "$crypt/trunc", 20, "initial file size" );
ok( truncate(OUT, 10), "truncate" );
is( -s "$crypt/trunc", 10, "truncated file size");
is( qx(cat "$crypt/trunc"), "1234567890", "truncated file contents");
# try growing the file as well.
ok( truncate(OUT, 30), "truncate extend");
is( -s "$crypt/trunc", 30, "truncated file size");
seek(OUT, 30, 0);
print OUT "12345";
is( -s "$crypt/trunc", 35, "truncated file size");
seek(OUT, 0, 0);
is( Digest::MD5->new->addfile(*OUT)->hexdigest,
"5f170cc34b1944d75d86cc01496292df", "content digest");
# try crossing block boundaries
seek(OUT, 10000,0);
print OUT "abcde";
seek(OUT, 0, 0);
is( Digest::MD5->new->addfile(*OUT)->hexdigest,
"117a51c980b64dcd21df097d02206f98", "content digest");
# then truncate back to 35 chars
truncate(OUT, 35);
seek(OUT, 0, 0);
is( Digest::MD5->new->addfile(*OUT)->hexdigest,
"5f170cc34b1944d75d86cc01496292df", "content digest");
close OUT;
}
sub fileCreation
{
# create a file
qx(df -ah > "$crypt/df.txt");
ok( -f "$crypt/df.txt", "file created" );
# ensure there is an encrypted version.
my $c = qx(./encfsctl encode --extpass="echo test" $raw df.txt);
chomp($c);
cmp_ok( length($c), '>', 8, "encrypted name ok" );
ok( -f "$raw/$c", "encrypted file created" );
# check contents
my $count = qx(grep -c crypt-$$ "$crypt/df.txt");
isnt(scalar($count), 0, "encrypted file readable");
unlink "$crypt/df.txt";
ok( ! -f "$crypt/df.txt", "file removal" );
ok( ! -f "$raw/$c", "file removal" );
}
sub checkContents
{
my ($file, $expected, $testName) = @_;
open(IN, "< $file");
my $line = <IN>;
is( $line, $expected, $testName );
close IN;
}
sub links
{
my $hardlinkTests = shift;
my $contents = "hello world\n";
ok( open(OUT, "> $crypt/data"), "create file for link test" );
print OUT $contents;
close OUT;
# symlinks
ok( symlink("$crypt/data", "$crypt/data-fqn") , "fqn symlink");
checkContents("$crypt/data-fqn", $contents, "fqn link traversal");
is( readlink("$crypt/data-fqn"), "$crypt/data", "read fqn symlink");
ok( symlink("data", "$crypt/data-rel"), "local symlink");
checkContents("$crypt/data-rel", $contents, "rel link traversal");
is( readlink("$crypt/data-rel"), "data", "read rel symlink");
SKIP: {
skip "No hardlink support" unless $hardlinkTests;
ok( link("$crypt/data", "$crypt/data.2"), "hard link");
checkContents("$crypt/data.2", $contents, "hardlink read");
};
}
sub mount
{
my $args = shift;
ok( ! -d $raw, "no existing dir");
ok( ! -d $crypt, "no existing dir");
mkdir $raw;
ok( -d $raw, "created dir" );
mkdir $crypt;
ok( -d $crypt, "created dir" );
qx(./encfs --extpass="echo test" $args $raw $crypt);
ok( -f "$raw/.encfs6.xml", "created control file");
}
sub cleanup
{
my $fusermount = qx(which fusermount);
if(-f $fusermount)
{
qx($fusermount -u "$crypt");
} else
{
qx(umount "$crypt");
}
rmdir $crypt;
ok( ! -d $crypt, "unmount ok, mount point removed");
if(-d $raw)
{
rmtree($raw);
}
ok( ! -d $raw, "encrypted directory removed");
}