Content Delivery Network (CDN) - optional, for either uploads only or both uploads & extras (rfe 9134)

This commit is contained in:
Randall Schwartz 2009-05-13 21:12:05 +00:00
parent d6696f8a7e
commit acd3fded45
8 changed files with 646 additions and 11 deletions

View file

@ -53,7 +53,7 @@ my @testSets = (
my $session = WebGUI::Test->session;
plan tests => scalar(@testSets) + 5;
plan tests => scalar(@testSets) + 6;
# generate
my $generateId = $session->id->generate();
@ -79,6 +79,7 @@ foreach my $testSet (@testSets) {
#
is($session->id->toHex('wjabZsKOb7kBBSiO3bQwzA'), 'c2369b66c28e6fb90105288eddb430cc', 'toHex works');
is($session->id->fromHex('c2369b66c28e6fb90105288eddb430cc'), 'wjabZsKOb7kBBSiO3bQwzA', 'fromHex works');
my $re = $session->id->getValidator;
is( ref $re, 'Regexp', 'getValidator returns a regexp object');

View file

@ -52,7 +52,7 @@ my @getRefererUrlTests = (
use Test::More;
use Test::MockObject::Extends;
plan tests => 72 + scalar(@getRefererUrlTests);
plan tests => 76 + scalar(@getRefererUrlTests);
my $session = WebGUI::Test->session;
@ -284,6 +284,12 @@ is($session->url->makeAbsolute('page1'), '/page1', 'makeAbsolute: default baseUr
my $origExtras = $session->config->get('extrasURL');
my $extras = $origExtras;
my $savecdn = $session->config->get('cdn');
if ($savecdn) {
$session->config->delete('cdn');
}
# Note: the CDN configuration will be reverted in the END
is($session->url->extras, $extras.'/', 'extras method returns URL to extras with a trailing slash');
is($session->url->extras('foo.html'), join('/', $extras,'foo.html'), 'extras method appends to the extras url');
is($session->url->extras('/foo.html'), join('/', $extras,'foo.html'), 'extras method removes extra slashes');
@ -301,8 +307,34 @@ $session->config->set('extrasURL', $extras);
is($session->url->extras('/foo.html'), join('', $extras,'foo.html'), 'extras method removes extra slashes');
is($session->url->extras('/dir1//foo.html'), join('', $extras,'dir1/foo.html'), 'extras method removes extra slashes anywhere');
$extras = 'http://mydomain.com/';
$session->config->set('extrasURL', $extras);
my $cdnCfg = { "enabled" => 1,
"extrasCdn" => "http://extras.example.com/",
"extrasSsl" => "https://ssl.example.com/",
"extrasExclude" => ["^tiny"]
};
$session->config->set('cdn', $cdnCfg);
is($session->url->extras('/dir1/foo.html'), join('', $cdnCfg->{extrasCdn}, 'dir1/foo.html'),
'extras cleartext with CDN');
is($session->url->extras('tinymce'), join('', $extras, 'tinymce'),
'extras exclusion from CDN');
# Note: env is already mocked above.
$mockEnv{HTTPS} = 'on';
is($session->url->extras('/dir1/foo.html'), join('', $cdnCfg->{extrasSsl}, 'dir1/foo.html'),
'extras using extrasSsl with HTTPS');
$mockEnv{HTTPS} = undef;
$mockEnv{SSLPROXY} = 1;
is($session->url->extras('/dir1/foo.html'), join('', $cdnCfg->{extrasSsl}, 'dir1/foo.html'),
'extras using extrasSsl with SSLPROXY');
delete $mockEnv{SSLPROXY};
$session->config->set('extrasURL', $origExtras);
# partial cleanup here; complete cleanup in END block
$session->config->delete('cdn');
#######################################
#
# escape and unescape
@ -468,4 +500,9 @@ END { ##Always clean-up
else {
$session->config->delete('webServerPort');
}
if ($savecdn) {
$session->config->set('cdn', $savecdn);
} else {
$session->config->delete('cdn');
}
}

View file

@ -29,7 +29,7 @@ my $cwd = Cwd::cwd();
my ($extensionTests, $fileIconTests) = setupDataDrivenTests($session);
my $numTests = 74; # increment this value for each test you create
my $numTests = 102; # increment this value for each test you create
plan tests => $numTests + scalar @{ $extensionTests } + scalar @{ $fileIconTests };
my $uploadDir = $session->config->get('uploadsPath');
@ -73,6 +73,12 @@ is( $storage1->getPathFrag, '7e/8a/7e8a1b6a', 'pathFrag returns correct value');
#
####################################################
my $savecdn = $session->config->get('cdn');
if ($savecdn) {
$session->config->delete('cdn');
}
# Note: the CDN configuration will be reverted after CDN tests below
my $storageDir1 = join '/', $uploadDir, '7e', '8a', '7e8a1b6a';
is ($storage1->getPath, $storageDir1, 'getPath: path calculated correctly for directory');
my $storageFile1 = join '/', $storageDir1, 'baz';
@ -369,6 +375,118 @@ foreach my $iconTest (@{ $fileIconTests }) {
is( $storage1->getFileIconUrl($iconTest->{filename}), $iconTest->{iconUrl}, $iconTest->{comment} );
}
####################################################
#
# CDN (Content Delivery Network)
#
####################################################
my $cdnCfg = { "enabled" => 1,
"url" => "file:///data/storage",
"queuePath" => "/data/cdnqueue",
"syncProgram" => "cp -r -- '%s' /data/storage/",
"deleteProgram" => "rm -r -- '/data/storage/%s' > /dev/null 2>&1"
};
my ($addedCdnQ, $addedCdnU);
$addedCdnQ = mkdir $cdnCfg->{'queuePath'} unless -e $cdnCfg->{'queuePath'};
my $dest = substr($cdnCfg->{'url'}, 7);
$addedCdnU = mkdir $dest unless -e $dest;
$session->config->set('cdn', $cdnCfg);
my $cdnUrl = $cdnCfg->{'url'};
my $cdnUlen = length $cdnUrl;
my $cdnStorage = WebGUI::Storage->create($session);
# 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');
# TODO: I'm not sure how to make these run on MS-Windows.
# Should we SKIP in the meantime? ($^O eq 'MSWin32')
### 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;
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');
####################################################
#
@ -452,8 +570,15 @@ END {
$storage1, $storage2, $storage3, $copiedStorage,
$secondCopy, $s3copy, $tempStor, $tarStorage,
$untarStorage, $fileStore,
$hackedStore,
$hackedStore, $cdnStorage, $cdnCopy,
) {
ref $stor eq "WebGUI::Storage" and $stor->delete;
}
if ($savecdn) {
$session->config->set('cdn', $savecdn);
} else {
$session->config->delete('cdn');
}
$addedCdnQ and rmdir $addedCdnQ;
$addedCdnU and rmdir $addedCdnU;
}