#------------------------------------------------------------------- # 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 = <() } $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); }