webgui/t/Storage.t
2011-05-31 16:13:09 -05:00

941 lines
34 KiB
Perl

#-------------------------------------------------------------------
# WebGUI is Copyright 2001-2009 Plain Black Corporation.
#-------------------------------------------------------------------
# Please read the legal notices (docs/legal.txt) and the license
# (docs/license.txt) that came with this distribution before using
# this software.
#-------------------------------------------------------------------
# http://www.plainblack.com info@plainblack.com
#-------------------------------------------------------------------
use FindBin;
use strict;
use lib "$FindBin::Bin/lib";
use WebGUI::Test;
use WebGUI::Test::Event;
use WebGUI::Session;
use WebGUI::Storage;
use File::Spec;
use File::Temp qw/tempdir/;
use Image::Magick;
use Test::More;
use Test::Deep;
use Test::MockObject;
use Cwd;
use Path::Class::Dir;
my $session = WebGUI::Test->session;
my $cwd = Cwd::cwd();
my ($extensionTests, $fileIconTests, $block_extension_tests) = setupDataDrivenTests($session);
plan tests => 164
+ scalar @{ $extensionTests }
+ scalar @{ $fileIconTests }
+ scalar @{ $block_extension_tests }
;
my $uploadDir = $session->config->get('uploadsPath');
ok ($uploadDir, "uploadDir defined in config");
my $uploadUrl = $session->config->get('uploadsURL');
ok ($uploadUrl, "uploadDir defined in config");
####################################################
#
# get, getId
#
####################################################
ok ((-e $uploadDir and -d $uploadDir), "uploadDir exists and is a directory");
my $storage1 = WebGUI::Storage->get($session);
is( $storage1, undef, "get requires id to be passed");
$storage1 = WebGUI::Storage->get($session, 'foobar');
WebGUI::Test->addToCleanup($storage1);
isa_ok( $storage1, "WebGUI::Storage", "storage will accept non GUID arguments");
is ( $storage1->getId, 'foobar', 'getId returns the requested GUID');
is( $storage1->getErrorCount, 0, "No errors during path creation");
is( $storage1->getLastError, undef, "No errors during path creation");
####################################################
#
# getPathFrag, getDirectoryId, get
#
####################################################
is( $storage1->getPathFrag, '7e/8a/7e8a1b6ab', 'pathFrag returns correct value');
is( $storage1->getDirectoryId, '7e8a1b6ab', 'getDirectoryId returns the last path element');
##Build an old-style GUID storage location
my $uploadsBase = Path::Class::Dir->new($uploadDir);
my $newGuid = $session->id->generate();
my @guidPathParts = (substr($newGuid, 0, 2), substr($newGuid, 2, 2), $newGuid);
my $guidDir = $uploadsBase->subdir(@guidPathParts);
$guidDir->mkpath();
ok(-e $guidDir->stringify, 'created GUID storage location for backwards compatibility testing');
my $guidStorage = WebGUI::Storage->get($session, $newGuid);
WebGUI::Test->addToCleanup($guidStorage);
isa_ok($guidStorage, 'WebGUI::Storage');
is($guidStorage->getId, $newGuid, 'GUID storage has correct id');
is($guidStorage->getDirectoryId, $newGuid, '... getDirectoryId');
####################################################
#
# getPath, getUrl
#
####################################################
WebGUI::Test->originalConfig('cdn');
$session->config->delete('cdn');
# Note: the CDN configuration will be reverted after CDN tests below
my $storageDir1 = join '/', $uploadDir, '7e', '8a', '7e8a1b6ab';
is ($storage1->getPath, $storageDir1, 'getPath: path calculated correctly for directory');
my $storageFile1 = join '/', $storageDir1, 'baz';
is ($storage1->getPath('baz'), $storageFile1, 'getPath: path calculated correctly for file');
my $storageUrl1 = join '/', $uploadUrl, '7e', '8a', '7e8a1b6ab';
is ($storage1->getUrl, $storageUrl1, 'getUrl: url calculated correctly for directory');
my $storageUrl2 = join '/', $storageUrl1, 'bar';
is ($storage1->getUrl('bar'), $storageUrl2, 'getUrl: url calculated correctly for file');
ok( (-e $storageDir1 and -d $storageDir1), "Storage location created and is a directory");
$storage1->delete;
ok( !(-e $storageDir1), "Storage location deleted");
undef $storage1;
$storage1 = WebGUI::Storage->get($session, 'notAGUID');
my $storage2 = WebGUI::Storage->get($session, 'notAGoodId');
WebGUI::Test->addToCleanup($storage2);
ok(! $storage2->getErrorCount, 'No errors due to a shared common root');
ok( (-e $storage1->getPath and -d $storage1->getPath), "Storage location 1 created and is a directory");
ok( (-e $storage2->getPath and -d $storage2->getPath), "Storage location 2 created and is a directory");
$storage1->delete;
undef $storage1;
ok( (-e $storage2->getPath and -d $storage2->getPath), "Storage location 2 not touched");
$storage2->delete;
my $storageDir2 = join '/', $uploadDir, 'no';
ok (!(-e $storageDir2), "Storage2 cleaned up properly");
undef $storage2;
## NOTE: On case insensitive file systems more matches can occur on this test
## and if all of these exist, then the next test will fail.
my @dirOptions = qw/bad bAd Bad BAd Zod God Mod Tod Rod Bod Lod/;
my ($dir3, $dirOpt);
CHECKDIR: while ($dirOpt = pop @dirOptions) {
$dir3 = join '/', $uploadDir, substr $dirOpt,0,2;
last CHECKDIR if !-e $dir3;
}
my $storage3 = WebGUI::Storage->get($session, $dirOpt);
WebGUI::Test->addToCleanup($storage3);
is( $storage3->getErrorCount, 1, 'Error during creation of object due to short GUID');
SKIP: {
skip 'All directory names already exist', 1 unless $dirOpt;
ok(!(-e $dir3 and -d $dir3), 'No directories created for short guid');
}
undef $storage3;
####################################################
#
# storageExists
#
####################################################
my $existingStorage = WebGUI::Storage->create($session);
WebGUI::Test->addToCleanup($existingStorage);
ok(WebGUI::Storage->storageExists($session, $existingStorage->getId), "storageExists returns true when the storage exists");
ok(!WebGUI::Storage->storageExists($session, 'Never_WebGUI_GUID'), "... and false when it doesn't");
####################################################
#
# create, getHexId
#
####################################################
$storage1 = WebGUI::Storage->create($session);
isa_ok( $storage1, "WebGUI::Storage");
ok($session->id->valid($storage1->getId), 'create returns valid sessionIds');
ok($storage1->getHexId, 'getHexId returns something');
is($storage1->getHexId, $session->id->toHex($storage1->getId), '... returns the hexadecimal value of the GUID');
{
my $otherStorage = WebGUI::Storage->get($session, $storage1->getId);
is($otherStorage->getHexId, $storage1->getHexId, '... works with get');
}
is( $storage1->getErrorCount, 0, "No errors during object creation");
ok ((-e $storage1->getPath and -d $storage1->getPath), 'directory created correctly');
my $content = <<EOCON;
Hi, I'm a file.
I have two lines.
EOCON
sub fired_ok(&@) {
my ($block, @expected) = @_;
my @events = trap { $block->() } $session, 'storage::addFile';
my @got = map { $_->[3] } @events;
cmp_bag \@got, \@expected, 'events fired for ' . join ', ', @expected;
}
my $filename; fired_ok {
$filename = $storage1->addFileFromScalar('content', $content)
} 'content';
is ($filename, 'content', 'processed filename returned by addFileFromScalar');
my $filePath = $storage1->getPath($filename);
ok ((-e $filePath and -T $filePath), 'file was created as a text file');
is (-s $filePath, length $content, 'file is the right size');
is ($storage1->getFileSize($filename), length $content, 'getFileSize returns correct size');
open my $fcon, "< ".$filePath or
die "Unable to open $filePath for reading: $!\n";
my $fileContents;
{
local $/;
$fileContents = <$fcon>;
}
close $fcon;
is ($fileContents, $content, 'file contents match');
is ($storage1->getFileContentsAsScalar($filename), $content, 'getFileContentsAsScalar matches');
isnt($/, undef, 'getFileContentsAsScalar did not change $/');
foreach my $extTest (@{ $extensionTests }) {
is( $storage1->getFileExtension($extTest->{filename}), $extTest->{extension}, $extTest->{comment} );
}
####################################################
#
# getFiles
#
####################################################
my $fileStore = WebGUI::Storage->create($session);
WebGUI::Test->addToCleanup($fileStore);
cmp_bag($fileStore->getFiles(1), ['.'], 'Starting with an empty storage object, no files in here except for . ');
fired_ok { $fileStore->addFileFromScalar('.dotfile', 'dot file') } '.dotfile';
cmp_bag($fileStore->getFiles(), [ ], 'getFiles() by default does not return dot files');
cmp_bag($fileStore->getFiles(1), ['.', '.dotfile'], 'getFiles(1) returns all files, including dot files');
fired_ok { $fileStore->addFileFromScalar('dot.file', 'dot.file') } 'dot.file';
cmp_bag($fileStore->getFiles(), ['dot.file'], 'getFiles() returns normal files');
cmp_bag($fileStore->getFiles(1), ['.', '.dotfile', 'dot.file'], 'getFiles(1) returns all files, including dot files');
####################################################
#
# getPathClassDir
#
####################################################
my $obj = $storage1->getPathClassDir;
isa_ok($obj, 'Path::Class::Dir');
is($obj->stringify, $storage1->getPath, '... Path::Class::Dir object has correct path');
####################################################
#
# addFileFromHashref
#
####################################################
my $storageHash = {'blah'=>"blah",'foo'=>"foo"};
fired_ok {
$storage1->addFileFromHashref("testfile-hash.file", $storageHash);
} 'testfile-hash.file';
ok (-e $storage1->getPath("testfile-hash.file"), 'addFileFromHashRef creates file');
####################################################
#
# getFileContentsAsHashref
#
####################################################
my $thawedHash = $storage1->getFileContentsAsHashref('testfile-hash.file');
cmp_deeply($storageHash, $thawedHash, 'getFileContentsAsHashref: thawed hash correctly');
####################################################
#
# copyFile
#
####################################################
$storage1->copyFile("testfile-hash.file", "testfile-hash-copied.file");
ok (-e $storage1->getPath("testfile-hash-copied.file"),'copyFile created file with new name');
ok (-e $storage1->getPath("testfile-hash.file"), "copyFile original file still exists");
####################################################
#
# renameFile
#
####################################################
$storage1->renameFile("testfile-hash.file", "testfile-hash-renamed.file");
ok (-e $storage1->getPath("testfile-hash-renamed.file"),'renameFile created file with new name');
ok (!(-e $storage1->getPath("testfile-hash.file")), "rename file original file is gone");
####################################################
#
# addFileFromFilesystem
#
####################################################
fired_ok {
$storage1->addFileFromFilesystem(
WebGUI::Test->getTestCollateralPath('littleTextFile'),
);
} 'littleTextFile';
ok(
grep(/littleTextFile/, @{ $storage1->getFiles }),
'addFileFromFilesystem: file added from test collateral area'
);
####################################################
#
# copy
#
####################################################
my $copiedStorage = $storage1->copy();
WebGUI::Test->addToCleanup($copiedStorage);
cmp_bag($copiedStorage->getFiles(), $storage1->getFiles(), 'copy: both storage objects have the same files');
my $secondCopy = WebGUI::Storage->create($session);
WebGUI::Test->addToCleanup($secondCopy);
$storage1->copy($secondCopy);
cmp_bag($secondCopy->getFiles(), $storage1->getFiles(), 'copy: passing explicit variable');
my $s3copy = WebGUI::Storage->create($session);
WebGUI::Test->addToCleanup($s3copy);
my @filesToCopy = qw/littleTextFile testfile-hash-renamed.file/;
$storage1->copy($s3copy, [@filesToCopy]);
cmp_bag($s3copy->getFiles(), [ @filesToCopy ], 'copy: passing explicit variable and files to copy');
{
my $deepStorage = WebGUI::Storage->create($session);
WebGUI::Test->addToCleanup($deepStorage);
my $deepDir = $deepStorage->getPathClassDir();
my $deepDeepDir = $deepDir->subdir('deep');
my $errorStr;
my @foo = $deepDeepDir->mkpath({ error => \$errorStr } );
fired_ok {
$deepStorage->addFileFromScalar('deep/file', 'deep file')
} 'deep/file';
cmp_bag(
$deepStorage->getFiles('all'),
[ '.', 'deep', 'deep/file' ],
'... storage setup for deep clear test'
);
my $deepCopy = $deepStorage->copy();
WebGUI::Test->addToCleanup($deepCopy);
cmp_bag(
$deepCopy->getFiles('all'),
[ '.', 'deep', 'deep/file' ],
'... all files copied, deeply'
);
}
####################################################
#
# deleteFile
#
####################################################
is(scalar @{ $storage1->getFiles }, 4, 'storage1 has 4 files');
is($storage1->deleteFile("testfile-hash-renamed.file"), 1, 'deleteFile: deleted 1 file');
is($storage1->deleteFile("testfile-hash-copied.file"), 1, 'deleteFile: deleted 1 file');
is($storage1->deleteFile("littleTextFile"), 1, 'deleteFile: deleted another file');
cmp_bag($storage1->getFiles, [$filename], 'deleteFile: storage1 has only 1 file');
##Test for out of object file deletion
my $hackedStore = WebGUI::Storage->create($session);
WebGUI::Test->addToCleanup($hackedStore);
$hackedStore->addFileFromScalar('fileToHack', 'Can this file be deleted from another object?');
ok(-e $hackedStore->getPath('fileToHack'), 'set up a file for deleteFile to try and delete illegally');
my $hackedPath = '../../../'.$hackedStore->getPathFrag().'/fileToHack';
is($storage1->deleteFile($hackedPath), undef, 'deleteFile into another storage returns undef');
ok(-e $hackedStore->getPath('fileToHack'), 'deleteFile did not delete the file in another storage object');
####################################################
#
# createTemp, getHexId
#
####################################################
my $tempStor = WebGUI::Storage->createTemp($session);
WebGUI::Test->addToCleanup($tempStor);
isa_ok( $tempStor, "WebGUI::Storage", "createTemp creates WebGUI::Storage object");
is (substr($tempStor->getPathFrag, 0, 5), 'temp/', '... puts stuff in the temp directory');
ok (-e $tempStor->getPath(), '... directory was created');
ok($tempStor->getHexId, '... getHexId returns something');
is($tempStor->getHexId, $session->id->toHex($tempStor->getId), '... returns the hexadecimal value of the GUID');
####################################################
#
# block_extensions
#
####################################################
##Run a set of extensions through and watch how the files get changed.
foreach my $extTest (@{ $block_extension_tests }) {
is( $storage1->block_extensions($extTest->{filename}), $extTest->{blockname}, $extTest->{comment} );
}
####################################################
#
# tar
#
####################################################
my $tarStorage = $copiedStorage->tar('tar.tar');
WebGUI::Test->addToCleanup($tarStorage);
isa_ok( $tarStorage, "WebGUI::Storage", "tar: returns a WebGUI::Storage object");
is (substr($tarStorage->getPathFrag, 0, 5), 'temp/', 'tar: puts stuff in the temp directory');
cmp_bag($tarStorage->getFiles(), [ 'tar.tar' ], 'tar: storage contains only the tar file');
isnt($tarStorage->getPath, $copiedStorage->getPath, 'tar did not reuse the same path as the source storage object');
####################################################
#
# untar
#
####################################################
my $untarStorage = $tarStorage->untar('tar.tar');
WebGUI::Test->addToCleanup($untarStorage);
isa_ok( $untarStorage, "WebGUI::Storage", "untar: returns a WebGUI::Storage object");
is (substr($untarStorage->getPathFrag, 0, 5), 'temp/', 'untar: puts stuff in the temp directory');
cmp_bag($untarStorage->getFiles, $copiedStorage->getFiles, 'tar and untar loop preserve all files');
isnt($untarStorage->getPath, $tarStorage->getPath, 'untar did not reuse the same path as the tar storage object');
$tarStorage->addFileFromFilesystem(WebGUI::Test->getTestCollateralPath('extensions.tar'));
my $extensionStorage = $tarStorage->untar('extensions.tar');
WebGUI::Test->addToCleanup($extensionStorage);
cmp_bag(
$extensionStorage->getFiles,
[ qw{ extension_pm.txt extension_perl.txt extension_html.txt extensions extensions/extension_html.txt }],
'untar fixes file extensions'
);
####################################################
#
# clear
#
####################################################
ok(scalar @{ $copiedStorage->getFiles } > 0, 'copiedStorage has some files');
$copiedStorage->clear;
cmp_bag(
$copiedStorage->getFiles('all'),
[ '.' ],
'clear removed all files from copiedStorage'
);
cmp_bag(
$copiedStorage->getFiles('all'),
[ '.' ],
'... removed _all_ files from copiedStorage, except for . and ..'
);
$copiedStorage->setPrivileges(3,3,3);
cmp_bag(
$copiedStorage->getFiles('all'),
[ '.', '.wgaccess' ],
'... removed _all_ files from copiedStorage, except for . and ..'
);
$copiedStorage->clear;
cmp_bag(
$copiedStorage->getFiles('all'),
[ '.' ],
'... removed .wgaccess file'
);
{
my $deepStorage = WebGUI::Storage->create($session);
WebGUI::Test->addToCleanup($deepStorage);
my $deepDir = $deepStorage->getPathClassDir();
my $deepDeepDir = $deepDir->subdir('deep');
my $errorStr;
$deepDeepDir->mkpath({ error => \$errorStr } );
$deepStorage->addFileFromScalar('deep/file', 'deep file');
cmp_bag(
$deepStorage->getFiles('all'),
[ '.', 'deep', 'deep/file' ],
'... storage setup for deep clear test'
);
$deepStorage->clear();
cmp_bag(
$deepStorage->getFiles('all'),
[ '.', ],
'... clear removes directories'
);
}
####################################################
#
# addFileFromFormPost
#
####################################################
$session->http->setStatus(413);
is($fileStore->addFileFromFormPost(), '', 'addFileFromFormPost returns empty string when HTTP status is 413');
$session->http->setStatus(200);
$session->request->upload('files', []);
my $formStore = WebGUI::Storage->create($session);
WebGUI::Test->addToCleanup($formStore);
is($formStore->addFileFromFormPost('files'), undef, 'addFileFromFormPost returns empty string when asking for a form variable with no files attached');
$session->request->uploadFiles(
'oneFile',
[ WebGUI::Test->getTestCollateralPath('littleTextFile') ],
);
fired_ok {
is($formStore->addFileFromFormPost('oneFile'), 'littleTextFile', '... returns the name of the uploaded file')
} 'littleTextFile';
cmp_bag($formStore->getFiles, [ qw/littleTextFile/ ], '... adds the file to the storage location');
$session->request->uploadFiles(
'thumbFile',
[ WebGUI::Test->getTestCollateralPath('thumb-thumb.gif') ],
);
is($formStore->addFileFromFormPost('thumbFile'), 'thumb.gif', '... strips thumb- prefix from files');
cmp_bag($formStore->getFiles, [ qw/littleTextFile thumb.gif/ ], '... adds the file to the storage location');
####################################################
#
# getFileIconUrl
#
####################################################
foreach my $iconTest (@{ $fileIconTests }) {
is( $storage1->getFileIconUrl($iconTest->{filename}), $iconTest->{iconUrl}, $iconTest->{comment} );
}
#----------------------------------------------------------------------------
# writeAccess
my $shallowStorage = WebGUI::Storage->create($session);
WebGUI::Test->addToCleanup($shallowStorage);
$shallowStorage->writeAccess( users => ["3"], groups => ["2"], assets => ["1"] );
my $shallowDir = $shallowStorage->getPathClassDir();
ok(-e $shallowDir->file('.wgaccess')->stringify, 'writeAccess: .wgaccess file created in shallow storage');
my $privs;
$privs = $shallowStorage->getFileContentsAsScalar('.wgaccess');
is ($privs, '{"assets":["1"],"groups":["2"],"users":["3"]}', '... correct group contents');
$shallowStorage->deleteFile('.wgaccess');
my $deepStorage = WebGUI::Storage->create($session);
WebGUI::Test->addToCleanup($deepStorage);
my $deepDir = $deepStorage->getPathClassDir();
my $deepDeepDir = $deepDir->subdir('deep');
my $errorStr;
$deepDeepDir->mkpath({ error => \$errorStr } );
ok(-e $deepDeepDir->stringify, 'created storage directory with a subdirectory for testing');
$deepStorage->writeAccess( users => ["3"], groups => ["2"], assets => ["1"] );
ok(-e $deepDir->file('.wgaccess')->stringify, '.wgaccess file created in deep storage');
ok(-e $deepDeepDir->file('.wgaccess')->stringify, '.wgaccess file created in deep storage subdir');
$privs = $deepStorage->getFileContentsAsScalar('.wgaccess');
is ($privs, '{"assets":["1"],"groups":["2"],"users":["3"]}', '... correct group contents, deep storage');
$privs = $deepStorage->getFileContentsAsScalar('deep/.wgaccess');
is ($privs, '{"assets":["1"],"groups":["2"],"users":["3"]}', '... correct group contents, deep storage subdir');
#----------------------------------------------------------------------------
# trash
my $shallowStorage = WebGUI::Storage->create($session);
WebGUI::Test->addToCleanup($shallowStorage);
$shallowStorage->trash;
my $shallowDir = $shallowStorage->getPathClassDir();
ok(-e $shallowDir->file('.wgaccess')->stringify, 'trash: .wgaccess file created in shallow storage');
my $privs;
$privs = $shallowStorage->getFileContentsAsScalar('.wgaccess');
is ($privs, '{"state":"trash"}', '... correct state');
$shallowStorage->deleteFile('.wgaccess');
my $deepStorage = WebGUI::Storage->create($session);
WebGUI::Test->addToCleanup($deepStorage);
my $deepDir = $deepStorage->getPathClassDir();
my $deepDeepDir = $deepDir->subdir('deep');
my $errorStr;
$deepDeepDir->mkpath({ error => \$errorStr } );
ok(-e $deepDeepDir->stringify, 'created storage directory with a subdirectory for testing');
$deepStorage->trash;
ok(-e $deepDir->file('.wgaccess')->stringify, '.wgaccess file created in deep storage');
ok(-e $deepDeepDir->file('.wgaccess')->stringify, '.wgaccess file created in deep storage subdir');
$privs = $deepStorage->getFileContentsAsScalar('.wgaccess');
is ($privs, '{"state":"trash"}', '... correct state contents, deep storage');
$privs = $deepStorage->getFileContentsAsScalar('deep/.wgaccess');
is ($privs, '{"state":"trash"}', '... correct state contents, deep storage subdir');
####################################################
#
# setPrivileges
#
####################################################
my $shallowStorage = WebGUI::Storage->create($session);
WebGUI::Test->addToCleanup($shallowStorage);
$shallowStorage->setPrivileges(3,3,3);
my $shallowDir = $shallowStorage->getPathClassDir();
ok(-e $shallowDir->file('.wgaccess')->stringify, 'setPrivilege: .wgaccess file created in shallow storage');
my $privs;
$privs = $shallowStorage->getFileContentsAsScalar('.wgaccess');
is ($privs, '{"assets":[],"groups":["3","3"],"users":["3"]}', '... correct group contents');
$shallowStorage->deleteFile('.wgaccess');
my $deepStorage = WebGUI::Storage->create($session);
WebGUI::Test->addToCleanup($deepStorage);
my $deepDir = $deepStorage->getPathClassDir();
my $deepDeepDir = $deepDir->subdir('deep');
my $errorStr;
$deepDeepDir->mkpath({ error => \$errorStr } );
ok(-e $deepDeepDir->stringify, 'created storage directory with a subdirectory for testing');
$deepStorage->setPrivileges(3,3,3);
ok(-e $deepDir->file('.wgaccess')->stringify, '.wgaccess file created in deep storage');
ok(-e $deepDeepDir->file('.wgaccess')->stringify, '.wgaccess file created in deep storage subdir');
$privs = $deepStorage->getFileContentsAsScalar('.wgaccess');
is ($privs, '{"assets":[],"groups":["3","3"],"users":["3"]}', '... correct group contents, deep storage');
$privs = $deepStorage->getFileContentsAsScalar('deep/.wgaccess');
is ($privs, '{"assets":[],"groups":["3","3"],"users":["3"]}', '... correct group contents, deep storage subdir');
{
my $storage = WebGUI::Storage->create($session);
WebGUI::Test->addToCleanup($storage);
my $asset = WebGUI::Asset->getRoot($session);
$storage->setPrivileges( $asset );
my $accessFile = $storage->getPathClassDir->file('.wgaccess');
ok(-e $accessFile, 'setPrivilege: .wgaccess file created for asset permissions');
my $privs = $accessFile->slurp;
is ($privs, '{"assets":["' . $asset->getId . '"],"groups":[],"users":[]}', '... correct asset contents');
}
####################################################
#
# rotate
#
####################################################
# Create new storage for test of 'rotate' method
my $rotateTestStorage = WebGUI::Storage->create($session);
WebGUI::Test->addToCleanup($rotateTestStorage);
# Add test image from file system
my $file = "rotation_test.png";
$rotateTestStorage->addFileFromFilesystem( WebGUI::Test->getTestCollateralPath($file) );
# Rotate image by 90° CW
$rotateTestStorage->rotate( $file, 90 );
# Test based on dimensions
cmp_deeply( [ $rotateTestStorage->getSizeInPixels($file) ], [ 3, 2 ], "rotate: check if image was rotated by 90° CW (based on dimensions)" );
# Test based on single pixel
my $image = new Image::Magick;
$image->Read( $rotateTestStorage->getPath( $file ) );
is( $image->GetPixel( x=>3, y=>1 ), 1, "rotate: check if image was rotated by 90° CW (based on pixels)");
# Rotate image by 90° CCW
$rotateTestStorage->rotate( $file, -90 );
# Test based on dimensions
cmp_deeply( [ $rotateTestStorage->getSizeInPixels($file) ], [ 2, 3 ], "rotate: check if image was rotated by 90° CCW (based on dimensions)" );
# Test based on single pixel
my $image = new Image::Magick;
$image->Read( $rotateTestStorage->getPath( $file ) );
is( $image->GetPixel( x=>1, y=>1 ), 1, "rotate: check if image was rotated by 90° CCW (based on pixels)");
####################################################
#
# CDN (Content Delivery Network)
#
####################################################
my $cdnTestPath = tempdir();
my $cdnQueueTestPath = tempdir();
my $cdnCfg = {
"enabled" => 1,
"url" => "file://$cdnTestPath",
"queuePath" => $cdnQueueTestPath,
"syncProgram" => "cp -r -- '%s' $cdnTestPath/",
"deleteProgram" => "rm -r -- '$cdnTestPath/%s' > /dev/null 2>&1"
};
my $dest = substr($cdnCfg->{'url'}, 7);
$session->config->set('cdn', $cdnCfg);
my $cdnUrl = $cdnCfg->{'url'};
my $cdnUlen = length $cdnUrl;
my $cdnStorage = WebGUI::Storage->create($session);
WebGUI::Test->addToCleanup($cdnStorage);
# Functional URL before sync done
my $hexId = $session->id->toHex($cdnStorage->getId);
my $initUrl = join '/', $uploadUrl, $cdnStorage->getPathFrag;
is ($cdnStorage->getUrl, $initUrl, 'CDN: getUrl: URL before sync');
$filename = $cdnStorage->addFileFromScalar('cdnfile1', $content);
is ($filename, 'cdnfile1', 'CDN: filename returned by addFileFromScalar');
my $qFile = $cdnCfg->{'queuePath'} . '/' . $session->id->toHex($cdnStorage->getId);
my $dotCdn = $cdnStorage->getPath . '/.cdn';
ok (-e $qFile, 'CDN: queue file created when file added to storage');
### getCdnFileIterator
my $found = 0;
my $sobj = undef;
my $flist;
my $cdnPath = substr($cdnUrl, 7) . '/' . $hexId;
my $cdnFn = $cdnPath . '/' . $filename;
my $locIter = WebGUI::Storage->getCdnFileIterator($session);
my $already; # test the object type only once
if (is(ref($locIter), 'CODE', 'CDN: getCdnFileIterator to return sub ref')) {
while (my $sobj = $locIter->()) {
unless ($already) {
ok($sobj->isa('WebGUI::Storage'), 'CDN: iterator produces Storage objects');
$already = 1;
}
if ($sobj->getId eq $cdnStorage->getId) { # the one we want to test with
++$found;
$flist = $sobj->getFiles;
if (is(scalar @$flist, 1, 'CDN: there is one file in the storage')) {
my $file1 = $flist->[0];
is ($file1, $filename, 'CDN: correct filename in the storage');
}
}
}
}
is ($found, 1, 'CDN: getCdnFileIterator found storage');
### syncToCdn
$cdnStorage->syncToCdn;
ok( (-e $cdnPath and -d $cdnPath), 'CDN: target directory created');
ok( (-e $cdnFn and -T $cdnFn), 'CDN: target text file created');
is (-s $cdnFn, length $content, 'CDN: file is the right size');
ok (!(-e $qFile), 'CDN: queue file removed after sync');
ok (-e $dotCdn, 'CDN: dot-cdn flag file present after sync');
### getUrl with CDN
my $locUrl = $cdnUrl . '/' . $session->id->toHex($cdnStorage->getId);
is ($cdnStorage->getUrl, $locUrl, 'CDN: getUrl: URL for directory');
my $fileUrl = $locUrl . '/' . 'cdn-file';
is ($cdnStorage->getUrl('cdn-file'), $fileUrl, 'CDN: getUrl: URL for file');
# SSL
my %mockEnv = %ENV;
my $env = Test::MockObject::Extends->new($session->env);
$env->mock('get', sub { return $mockEnv{$_[1]} } );
$mockEnv{HTTPS} = 'on';
$cdnCfg->{'sslAlt'} = 1;
$session->config->set('cdn', $cdnCfg);
is ($cdnStorage->getUrl, $initUrl, 'CDN: getUrl: URL with sslAlt flag');
$cdnCfg->{'sslUrl'} = 'https://ssl.example.com';
$session->config->set('cdn', $cdnCfg);
my $sslUrl = $cdnCfg->{'sslUrl'} . '/' . $session->id->toHex($cdnStorage->getId);
is ($cdnStorage->getUrl, $sslUrl, 'CDN: getUrl: sslUrl');
$mockEnv{HTTPS} = undef;
is ($cdnStorage->getUrl, $locUrl, 'CDN: getUrl: cleartext request to not use sslUrl');
# Copy
my $cdnCopy = $cdnStorage->copy;
WebGUI::Test->addToCleanup($cdnCopy);
my $qcp = $cdnCfg->{'queuePath'} . '/' . $session->id->toHex($cdnCopy->getId);
ok (-e $qcp, 'CDN: queue file created when storage location copied');
my $dotcp = $cdnCopy->getPath . '/.cdn';
ok (!(-e $dotcp), 'CDN: dot-cdn flag file absent after copy');
# On clear, need to see the entry in cdnQueue
$qFile = $cdnCfg->{'queuePath'} . '/' . $session->id->toHex($cdnStorage->getId);
$cdnStorage->clear;
ok (-e $qFile, 'CDN: queue file created when storage cleared');
ok (-s $qFile >= 7 && -s $qFile <= 9, 'CDN: queue file has right size for deleted (clear)');
ok (!(-e $dotCdn), 'CDN: dot-cdn flag file absent after clear');
### deleteFromCdn
$cdnStorage->deleteFromCdn;
ok(! (-e $cdnPath), 'CDN: target directory removed');
ok(! (-e $qFile), 'CDN: queue file removed');
# Idea: add a file back before testing delete
# Note: expect it is necessary to be able to delete after clear.
# On delete, need to see the entry in cdnQueue
$cdnStorage->delete;
ok (-e $qFile, 'CDN: queue file created when storage deleted');
ok (-s $qFile >= 7 && -s $qFile <= 9, 'CDN: queue file has right size for deleted');
$cdnStorage->deleteFromCdn;
ok(! (-e $qFile), 'CDN: queue file removed');
# partial cleanup here; complete cleanup in END block
undef $cdnStorage;
$session->config->delete('cdn');
####################################################
#
# Test what happens when the directory for a
# storage object does not exist.
#
####################################################
my $zombieStorage = WebGUI::Storage->create($session);
WebGUI::Test->addToCleanup($zombieStorage);
my $zombieDir = $zombieStorage->getPathClassDir;
$zombieDir->remove;
is( $zombieStorage->getPathClassDir, undef, 'bad storage: getPathClassDir returns undef');
cmp_deeply( $zombieStorage->getFiles, [], '... getFiles returns an empty array ref');
cmp_deeply( $zombieStorage->setPrivileges, undef, '... setPrivileges returns undef');
cmp_deeply( $zombieStorage->clear, undef, '... setPrivileges returns undef');
####################################################
#
# Make sure after all this that our CWD is still the same
#
####################################################
is($cwd, Cwd::cwd(), 'CWD must remain the same after addFileFromFilesystem, tar, untar, etc...');
####################################################
#
# Setup data driven tests here, to keep the top part of the
# test clean.
#
####################################################
sub setupDataDrivenTests {
my $session = shift;
my $extensionTests = [
{
filename => 'filename',
extension => undef,
comment => 'no extension',
},
{
filename => 'filename.',
extension => '',
comment => 'dot, but no extension',
},
{
filename => 'filename.txt',
extension => 'txt',
comment => 'simple extension',
},
{
filename => 'filename.TXT',
extension => 'txt',
comment => 'extensions are all lowercase',
},
{
filename => 'filename.FOO.BAR',
extension => 'bar',
comment => 'multiple extensions return last extension',
},
];
my $block_extension_tests = [
{
filename => 'filename',
blockname => 'filename',
comment => 'no extension',
},
{
filename => 'filename.pl',
blockname => 'filename_pl.txt',
comment => 'pl file',
},
{
filename => 'filename.perl',
blockname => 'filename_perl.txt',
comment => 'perl file',
},
{
filename => 'filename.cgi',
blockname => 'filename_cgi.txt',
comment => 'cgi file',
},
{
filename => 'filename.php',
blockname => 'filename_php.txt',
comment => 'php file',
},
{
filename => 'filename.asp',
blockname => 'filename_asp.txt',
comment => 'asp file',
},
{
filename => 'filename.pm',
blockname => 'filename_pm.txt',
comment => 'perl module file',
},
{
filename => 'filename.htm',
blockname => 'filename_htm.txt',
comment => 'htm file',
},
{
filename => 'filename.html',
blockname => 'filename_html.txt',
comment => 'html file',
},
{
filename => 'filename.pm.txt',
blockname => 'filename.pm.txt',
comment => 'internal .pm not touched',
},
{
filename => 'filename.txt.pm',
blockname => 'filename.txt_pm.txt',
comment => 'double extension handled',
},
];
my $fileIconTests = [
{
filename => 'filename',
iconUrl => $session->url->extras("fileIcons/unknown.gif"),
comment => 'no extension uses unknown icon',
},
{
filename => 'filename.txt',
iconUrl => $session->url->extras("fileIcons/txt.gif"),
comment => 'valid extension, lower case works',
},
{
filename => 'filename.TXT',
iconUrl => $session->url->extras("fileIcons/txt.gif"),
comment => 'valid extension, upper case works',
},
{
filename => 'filename.00TXT00',
iconUrl => $session->url->extras("fileIcons/unknown.gif"),
comment => 'unknown extension',
},
];
return ($extensionTests, $fileIconTests, $block_extension_tests);
}