3
* Gallery - a web based photo album viewer and editor
4
* Copyright (C) 2000-2007 Bharat Mediratta
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or (at
9
* your option) any later version.
11
* This program is distributed in the hope that it will be useful, but
12
* WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
22
* ItemAddFromServer plugin test
25
* @author Bharat Mediratta <bharat@menalto.com>
26
* @version $Revision: 15513 $
28
class ItemAddFromServerTest extends ItemAddPluginTestCase {
30
function ItemAddFromServerTest($methodName) {
31
$this->ItemAddPluginTestCase($methodName, 'itemadd', 'ItemAddFromServer');
39
list ($ret, $this->_rootAlbum) =
40
$this->_createRandomAlbum($this->_getRootId(), array('orderBy' => 'orderWeight'));
42
print $ret->getAsHtml();
43
return $this->failWithStatus($ret);
45
$this->_markForCleanup($this->_rootAlbum);
47
list ($ret, $this->_lockId) = GalleryCoreApi::acquireReadLock($this->_rootAlbum->getId());
49
print $ret->getAsHtml();
50
return $this->failWithStatus($ret);
53
$this->_symlinkAllowedPlatform =
54
new ItemAddFromServerTestPlatform($gallery->getPlatform(), true);
55
$this->_symlinkDisallowedPlatform =
56
new ItemAddFromServerTestPlatform($gallery->getPlatform(), false);
58
$ret = $this->_markPluginParametersForCleanup('module', 'itemadd');
60
print $ret->getAsHtml();
61
return $this->failWithStatus($ret);
64
$this->_baseDir = dirname(dirname(__FILE__));
65
$ret = GalleryCoreApi::setPluginParameter('module', 'itemadd', 'uploadLocalServer.dir.1',
68
print $ret->getAsHtml();
69
return $this->failWithStatus($ret);
71
$ret = GalleryCoreApi::setPluginParameter('module', 'itemadd', 'uploadLocalServer.dir.2',
72
$gallery->getConfig('data.gallery.base'));
74
print $ret->getAsHtml();
75
return $this->failWithStatus($ret);
77
$ret = GalleryCoreApi::removePluginParameter('module', 'itemadd',
78
'uploadLocalServer.dir.3');
80
print $ret->getAsHtml();
81
return $this->failWithStatus($ret);
84
$gallery->setPlatform($this->_symlinkAllowedPlatform);
88
$ret = GalleryCoreApi::releaseLocks($this->_lockId);
90
return $this->failWithStatus($ret);
96
function testIsAppropriate() {
97
$ret = GalleryCoreApi::setPluginParameter('module', 'itemadd', 'fromserver', 'off');
99
return $this->failWithStatus($ret);
101
list ($ret, $isAppropriate) = $this->_plugin->isAppropriate();
103
return $this->failWithStatus($ret);
105
$this->assertEquals(false, $isAppropriate, 'off');
107
$ret = GalleryCoreApi::setPluginParameter('module', 'itemadd', 'fromserver', 'admin');
109
return $this->failWithStatus($ret);
111
list ($ret, $isAppropriate) = $this->_plugin->isAppropriate();
113
return $this->failWithStatus($ret);
115
$this->assertEquals(true, $isAppropriate, 'admin for admin');
117
$this->_becomeGuestUser();
118
list ($ret, $isAppropriate) = $this->_plugin->isAppropriate();
120
return $this->failWithStatus($ret);
122
$this->assertEquals(false, $isAppropriate, 'admin for guest');
124
$ret = GalleryCoreApi::setPluginParameter('module', 'itemadd', 'fromserver', 'on');
126
return $this->failWithStatus($ret);
128
list ($ret, $isAppropriate) = $this->_plugin->isAppropriate();
130
return $this->failWithStatus($ret);
132
$this->assertEquals(true, $isAppropriate, 'on');
136
* call _testAddChildrenFromLocalServer with the '$useSymlink'
137
* parameter set to false, thus specifying that the files should be copied.
139
function testAddChildrenFromLocalServer() {
140
return $this->_testAddChildrenFromLocalServer(false);
145
* call _testAddChildrenFromLocalServer specifying that we want to use
146
* a symlink. Also specify that the symlink should be supported (and
147
* thus the mock platform object that supports symlinks will be used.
149
function testAddChildrenFromLocalServerUsingSymlinkWithSymlinkSupported() {
150
return $this->_testAddChildrenFromLocalServer(true, true);
155
* call _testAddChildrenFromLocalServer specifying that we want to use
156
* a symlink. Also specify that the symlink should >not< be supported
157
* (and thus the mock platform object that does not support symlinks will be used.
159
function testAddChildrenFromLocalServerUsingSymlinkWithSymlinkNotSupported() {
160
return $this->_testAddChildrenFromLocalServer(true, false);
165
* call _testAddChildrenFromLocalServer with setTitle (set to base filename)
167
function testAddChildrenFromLocalServerSetTitle() {
168
return $this->_testAddChildrenFromLocalServer(false, true, true, false, true);
173
* call _testAddChildrenFromLocalServer with setTitle/setDescription (set to base filename)
175
function testAddChildrenFromLocalServerSetTitleDescription() {
176
return $this->_testAddChildrenFromLocalServer(false, true, true, false, true, false, true);
179
function testAddChildrenFromLocalServerRecursive() {
180
return $this->_testAddChildrenFromLocalServer(false, true, false, true);
183
function testAddChildrenFromLocalServerRecursiveUsingSymlinkWithSymlinkSupported() {
184
return $this->_testAddChildrenFromLocalServer(true, true, false, true);
187
function testAddChildrenFromLocalServerRecursiveUsingSymlinkWithSymlinkNotSupported() {
188
return $this->_testAddChildrenFromLocalServer(true, false, false, true);
191
function testAddChildrenFromLocalServerRecursiveSetSummaryDescription() {
192
return $this->_testAddChildrenFromLocalServer(false, true, false, true, false, true, true);
196
* All 'testAddChildrenFromLocalServer*' tests are very similar, hence
197
* they all run through this method. The two parameters to this method
198
* are: '$useSymlink', which is a boolean specifying if we should try
199
* to add the files using a symlink or not. The second param is
200
* '$shouldSucceed'. Since windows based OSes don't support symlinks,
201
* G2 will not support adding a file using symlinks on those OSes.
202
* We have two different mock platform objects, one that supports
203
* symlinks and one that does not. If we expect using a symlink to
204
* fail, we bail check for that condition, and then bail out immediately.
206
function _testAddChildrenFromLocalServer($useSymlink, $symlinkSupported=true,
207
$addFiles=true, $addDirectories=false,
208
$setTitle=false, $setSummary=false,
209
$setDescription=false) {
213
* Use b<->a comparison here and rsort below because sanitizeInputValues on
214
* form input will sanitize apo\'strophe.jpg and move it to the "end" of the
215
* array, no matter what order we use to construct form[localServerFiles].
216
* rsort keeps this item at the end anyway, so we get the expected results.
218
$sortAddedFilesFunc = create_function('$a, $b',
219
'return strcmp($b[\'fileName\'], $a[\'fileName\']);');
221
if ($symlinkSupported) {
222
$gallery->setPlatform($this->_symlinkAllowedPlatform);
224
$gallery->setPlatform($this->_symlinkDisallowedPlatform);
227
/* Use valid inputs */
228
GalleryUtilities::putRequestVariable('form[action][addFromLocalServer]', 1);
230
GalleryUtilities::putRequestVariable('form[set][title]', 1);
233
GalleryUtilities::putRequestVariable('form[set][summary]', 1);
235
if ($setDescription) {
236
GalleryUtilities::putRequestVariable('form[set][description]', 1);
239
$platform =& $gallery->getPlatform();
240
$dirSep = $platform->getDirectorySeparator();
241
$baseDir = $this->_baseDir . $dirSep . 'data';
245
/* Some simple filenames and some with special characters */
246
$files = array('test1.gif', 'test1.jpg', 'test2.gif', 'test[3].gif',
247
'apo\'strophe.jpg', "t\xebst.png");
251
array('test1', 'test1', 'test2', 'test[3]', 'apo\'strophe', "t\xebst");
252
rsort($escapedBasenames);
254
foreach ($files as $fileName) {
255
$fileName = urlencode($fileName);
256
GalleryUtilities::putRequestVariable(
257
'form[localServerFiles][' . $fileName . '][selected]', 1);
259
GalleryUtilities::putRequestVariable(
260
'form[localServerFiles][' . $fileName . '][useSymlink]', 1);
265
if ($addDirectories) {
266
$files = array('test1.gif', 'test1.jpg', 'test2.gif', 'test[3].gif', 'test4.gif');
269
$escapedBasenames = array('test1', 'test1', 'test2', 'test[3]', 'test4');
270
rsort($escapedBasenames);
272
$dirs = array('localUploadDir', "subD\xeer", '..');
273
foreach ($dirs as $dirName) {
274
$dirName = urlencode($dirName);
275
GalleryUtilities::putRequestVariable(
276
'form[localServerDirectories][' . $dirName . '][selected]', 1);
278
GalleryUtilities::putRequestVariable(
279
'form[localServerDirectories][' . $dirName . '][useSymlink]', 1);
282
/* .. is invalid and will be ignored, don't expect it in results */
286
GalleryUtilities::putRequestVariable('form[localServerPath]',
287
GalleryCoreApi::convertToUtf8($baseDir));
289
/* Perform the request and verify that we succeeded */
290
if ($symlinkSupported) {
291
$results = $this->handleRequest($this->_rootAlbum);
293
$results = $this->handleRequest($this->_rootAlbum, ERROR_UNSUPPORTED_OPERATION);
294
/* Set the mock platform back to the one that supports symlink for consistency */
295
$gallery->setPlatform($this->_symlinkAllowedPlatform);
298
$this->assertEquals(array(), $results[0]);
300
/* We don't know the ids, but we can verify everything else */
302
$this->assertEquals(count($files), count($results[1]['addedFiles']), 'added count');
303
usort($results[1]['addedFiles'], $sortAddedFilesFunc);
304
foreach ($files as $file) {
305
$this->assertEquals(GalleryCoreApi::convertToUtf8($file),
306
$results[1]['addedFiles'][$i]['fileName'], 'added #' . $i);
307
$this->assert(isset($results[1]['addedFiles'][$i]['id']));
311
/* Verify item attributes (like order weight) */
312
list ($ret, $ids) = GalleryCoreApi::fetchChildItemIds($this->_rootAlbum);
314
return $this->failWithStatus($ret);
316
if ($addDirectories) {
317
$this->assertEquals(count($dirs), count($ids), 'top child count');
318
list ($ret, $subalbums) = GalleryCoreApi::loadEntitiesById($ids);
320
return $this->failWithStatus($ret);
322
list ($ret, $ids) = GalleryCoreApi::fetchChildItemIds($subalbums[0]);
324
return $this->failWithStatus($ret);
326
foreach ($dirs as $dirName) {
327
$subalbum = array_shift($subalbums);
328
$this->assert(GalleryUtilities::isA($subalbum, 'GalleryAlbumItem'), 'subalbum');
329
$dirName = $platform->legalizePathComponent($dirName);
330
$this->assertEquals($dirName, $subalbum->getPathComponent(), 'subalbum path');
333
$addDirectoriesString = $addDirectories ? ' addDirectories' : ' !addDirectories';
334
$this->assertEquals(count($files), count($ids), 'child count' . $addDirectoriesString);
336
list ($ret, $items) = GalleryCoreApi::loadEntitiesById($ids);
338
return $this->failWithStatus($ret);
341
/* Organize items array by id */
343
foreach ($items as $item) {
344
$newItems[$item->getId()] = $item;
348
$seenWeights = array();
350
foreach ($escapedBasenames as $base) {
351
$item =& $items[$results[1]['addedFiles'][$i]['id']];
353
$this->assert(false, 'Item ' . $i++ . ' missing');
356
$expectedName = GalleryCoreApi::convertToUtf8($base);
357
$this->assertEquals($setTitle ? $expectedName : '', $item->getTitle(), 'title');
358
$this->assertEquals($setSummary ? $expectedName : '', $item->getSummary(),
360
$this->assertEquals($setDescription ? $expectedName : '', $item->getDescription(),
363
$this->assertEquals($platform->legalizePathComponent($files[$i]),
364
$item->getPathComponent(), 'path component ' . $i);
366
list ($ret, $viewCount) = GalleryCoreApi::fetchItemViewCount($item->getId());
368
return $this->failWithStatus($ret);
370
$this->assertEquals(0, $viewCount);
372
list ($ret, $orderWeight) = GalleryCoreApi::fetchItemOrderWeight($item->getId());
374
return $this->failWithStatus($ret);
376
$this->assert(!isset($seenWeights[$item->getParentId()][$orderWeight]),
377
'Seen this weight before: ' . $orderWeight);
378
$seenWeights[$item->getParentId()][$orderWeight] = 1;
383
function testInvalidLocalServerPath() {
384
GalleryUtilities::putRequestVariable('form[action][addFromLocalServer]', 1);
385
GalleryUtilities::putRequestVariable('form[localServerPath]', '/');
386
GalleryUtilities::putRequestVariable(
387
'form[localServerFiles][ItemAddFromServerTest.foo][selected]', 1);
388
$this->handleRequest($this->_rootAlbum, ERROR_BAD_PARAMETER);
392
* Checks if the urlencoded filename gets correctly converted to a nice filename
393
* in pathComponent, title and summary
395
function testAddFromServerFilenameToFields() {
397
$platform =& $gallery->getPlatform();
398
$dirSep = $platform->getDirectorySeparator();
399
$baseDir = $this->_baseDir . $dirSep . 'data';
401
GalleryUtilities::putRequestVariable('form[action][addFromLocalServer]', 1);
402
GalleryUtilities::putRequestVariable('form[localServerPath]', $baseDir);
403
GalleryUtilities::putRequestVariable('form[set][title]', 1);
404
GalleryUtilities::putRequestVariable('form[set][summary]', 1);
405
/* This is what the browser will send us (urlencoded): */
406
GalleryUtilities::putRequestVariable(
407
'form[localServerFiles][' . urlencode('December - <#952>.jpg') . '][selected]', 1);
409
$results = $this->handleRequest($this->_rootAlbum);
410
$this->assertEquals(array(), $results[0]);
411
$this->assertEquals(1, count($results[1]));
412
$this->assertEquals(1, count($results[1]['addedFiles']));
414
list ($ret, $item) = GalleryCoreApi::loadEntitiesById($results[1]['addedFiles'][0]['id']);
416
return $this->failWithStatus($ret);
418
$this->assertEquals('December - _#952_.jpg', $item->getPathComponent(), 'pathComponent');
419
$this->assertEquals('December - <#952>', $item->getTitle(), 'title');
420
$this->assertEquals('December - <#952>', $item->getSummary(), 'summary');
421
$this->assertEquals('', $item->getDescription(), 'description');
425
* Checks that we disallow recursive add from our own g2data directory.
427
function testAddFromServerG2DataDir() {
430
list ($ret, $path) = $this->_rootAlbum->fetchPath();
432
return $this->failWithStatus($ret);
435
GalleryUtilities::putRequestVariable('form[action][addFromLocalServer]', 1);
436
GalleryUtilities::putRequestVariable('form[localServerPath]', dirname($path));
437
GalleryUtilities::putRequestVariable('form[set][title]', 1);
438
GalleryUtilities::putRequestVariable('form[localServerDirectories][' .
439
urlencode(basename($path)) . '][selected]', 1);
441
$results = $this->handleRequest($this->_rootAlbum);
442
$this->assertEquals(array(array(), array()), $results);
445
function testAddFromServerMalformedInput() {
446
/* Test that manually constructed input can't get outside our approved dirs */
448
$platform =& $gallery->getPlatform();
449
$dirSep = $platform->getDirectorySeparator();
450
$baseDir = $this->_baseDir . $dirSep;
452
GalleryUtilities::putRequestVariable('form[action][addFromLocalServer]', 1);
453
GalleryUtilities::putRequestVariable('form[localServerPath]', $baseDir);
454
GalleryUtilities::putRequestVariable('form[localServerFiles][..%2Ffoo][selected]', 1);
455
GalleryUtilities::putRequestVariable('form[localServerDirectories][..%2Fbar][selected]', 1);
456
GalleryUtilities::putRequestVariable('form[set][title]', 1);
458
$results = $this->handleRequest($this->_rootAlbum);
459
$this->assertEquals(array(array(), array()), $results);
462
function testAddFromServerEntityDir() {
463
/* Test that characters in dirname that get entitized still work ok */
465
$platform =& $gallery->getPlatform();
466
$dirSep = $platform->getDirectorySeparator();
467
$baseDir = $this->_baseDir . $dirSep . 'data' . $dirSep;
469
GalleryUtilities::putRequestVariable('form[action][addFromLocalServer]', 1);
470
GalleryUtilities::putRequestVariable('form[localServerPath]', $baseDir . '<My "Files">');
471
GalleryUtilities::putRequestVariable('form[localServerFiles][foo][selected]', 1);
472
GalleryUtilities::putRequestVariable('form[set][title]', 1);
474
$results = $this->handleRequest($this->_rootAlbum);
475
if (empty($results[1]['addedFiles'][0]['id'])) {
476
$this->assert(false, 'missing id of added item');
478
$id = $results[1]['addedFiles'][0]['id'];
479
$this->assertEquals(array(array(), array('addedFiles' =>
480
array(array('fileName' => 'foo', 'id' => $id, 'warnings' => array())))), $results);
488
class ItemAddFromServerTestPlatform extends GalleryPlatform {
489
function ItemAddFromServerTestPlatform($delegate, $symlinkSupported) {
490
$this->_delegate = $delegate;
491
$dirSep = $this->_dirSep = $delegate->getDirectorySeparator();
492
$this->_symlinkSupported = $symlinkSupported;
493
$this->_baseDir = dirname(dirname(__FILE__)) . "{$dirSep}data{$dirSep}";
494
$this->_baseDirRecursive = dirname(dirname(__FILE__)) .
495
"{$dirSep}..{$dirSep}data{$dirSep}localUploadDir{$dirSep}";
499
* Simply collapse .. clauses out of paths. If we use realpath() it'll try to verify that the
500
* path actually exists (which it won't, in some cases)
502
function realpath($path) {
503
return preg_replace('#[^\\\/]+[\\\/]\.\.([\\\/]|$)#', '', $path);
506
function file_exists($path) {
508
case $this->_baseDir . 'December - <#952>.jpg':
509
case $this->_baseDir . '<My "Files">' . $this->_dirSep . 'foo':
510
case $this->_baseDir . "t\xebst.png":
511
case $this->_baseDir . 'apo\'strophe.jpg':
512
case $this->_baseDirRecursive . 'apo\'strophe.jpg':
513
/* The windows path is a little weird -- but we can live with it */
514
case $this->_baseDir . '\\apo\'strophe.jpg':
518
return $this->_delegate->file_exists($path);
522
function copy($source, $dest) {
524
case $this->_baseDir . 'December - <#952>.jpg':
525
case $this->_baseDir . '<My "Files">' . $this->_dirSep . 'foo':
526
case $this->_baseDir . "t\xebst.png":
527
case $this->_baseDir . 'apo\'strophe.jpg':
528
case $this->_baseDirRecursive . 'apo\'strophe.jpg':
529
/* The windows path is a little weird -- but we can live with it */
530
case $this->_baseDir . '\\apo\'strophe.jpg':
531
case $this->_baseDirRecursive . '\\apo\'strophe.jpg':
532
$source = $this->_baseDir . 'test1.jpg';
535
return $this->_delegate->copy($source, $dest);
538
function symlink($source, $dest) {
540
case $this->_baseDir . 'December - <#952>.jpg':
541
case $this->_baseDir . "t\xebst.png":
542
case $this->_baseDir . 'apo\'strophe.jpg':
543
case $this->_baseDirRecursive . 'apo\'strophe.jpg':
544
/* The windows path is a little weird -- but we can live with it */
545
case $this->_baseDir . '\\apo\'strophe.jpg':
546
case $this->_baseDirRecursive . '\\apo\'strophe.jpg':
547
$source = $this->_baseDir . 'test1.jpg';
551
if ($this->_delegate->isSymlinkSupported()) {
552
return $this->_delegate->symlink($source, $dest);
554
return $this->copy($source, $dest);
558
function isSymlinkSupported() {
559
return $this->_symlinkSupported;
562
function opendir($path) {
563
if ($path == $this->_baseDir . "subD\xeer") {
566
return $this->_delegate->opendir($path);
569
function readdir($resource) {
570
if ($resource === 'testHandle') {
573
return $this->_delegate->readdir($resource);
576
function closedir($resource) {
577
if ($resource === 'testHandle') {
580
return $this->_delegate->closedir($resource);
583
function exec($cmd) {
584
/* In case add of jpeg tries to get 'colorspace' property */
585
return array(true, array(''), array());