1<?php 2// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project 3// 4// All Rights Reserved. See copyright.txt for details and a complete list of authors. 5// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details. 6// $Id$ 7 8namespace Tiki\Test\Files; 9 10use org\bovigo\vfs\vfsStream; 11use Tiki\Files\CheckAttachmentGallery; 12use TikiLib; 13 14class CheckAttachmentGalleryTest extends \PHPUnit_Framework_TestCase 15{ 16 protected $file_root; 17 protected $files_dir; 18 protected $default_file_content = 'this is a test'; 19 20 protected function setUp() 21 { 22 global $prefs; 23 24 $prefs['feature_user_watches'] = 'n'; 25 $this->refreshDirectory(); 26 // Remove existing attachments 27 $this->removeAttachmentsFromDb(); 28 } 29 30 protected function tearDown() 31 { 32 $this->removeAttachmentsFromDb(); 33 } 34 35 /** 36 * @dataProvider getTypes 37 * @param $type 38 */ 39 public function testAttachmentEmptyAttachmentsNoProblemOnDB($type) 40 { 41 $to_assert = [ 42 'usesDatabase' => true, 43 'path' => [''], 44 'mixedLocation' => false, 45 'count' => 0, 46 'countFilesDb' => 0, 47 'countFilesDisk' => 0, 48 'issueCount' => 0, 49 'missing' => [], 50 'mismatch' => [], 51 'unknown' => [], 52 ]; 53 54 $this->configToStoreFiles($type, true); 55 $checkInstance = new CheckAttachmentGallery($type); 56 57 $result = $checkInstance->analyse(); 58 59 $this->assertEquals($to_assert, $result); 60 } 61 62 /** 63 * @dataProvider getTypes() 64 */ 65 public function testAttachmentEmptyAttachmentsNoProblemOnDisk($type) 66 { 67 $to_assert = [ 68 'usesDatabase' => false, 69 'path' => [$this->files_dir], 70 'mixedLocation' => false, 71 'count' => 0, 72 'countFilesDb' => 0, 73 'countFilesDisk' => 0, 74 'issueCount' => 0, 75 'missing' => [], 76 'mismatch' => [], 77 'unknown' => [], 78 ]; 79 80 $this->configToStoreFiles($type, false); 81 $checkInstance = new CheckAttachmentGallery($type); 82 83 $result = $checkInstance->analyse(); 84 85 $this->assertEquals($to_assert, $result); 86 } 87 88 /** 89 * @dataProvider getTypes 90 * @throws \Exception 91 */ 92 public function testAttachmentWithOneFileOnDisk($type) 93 { 94 $this->configToStoreFiles($type, false); 95 96 $this->insertAttachment(['name' => uniqid(), 'type' => $type]); 97 98 $checkInstance = new CheckAttachmentGallery($type); 99 $result = $checkInstance->analyse(); 100 101 $this->assertFalse($result['usesDatabase']); 102 $this->assertFalse($result['mixedLocation']); 103 $this->assertEquals(1, $result['count']); 104 $this->assertEquals(0, $result['issueCount']); 105 } 106 107 /** 108 * @dataProvider getTypes() 109 * @param $type 110 * @throws \Exception 111 */ 112 public function testAttachmentWithOneFileOnDb($type) 113 { 114 $this->configToStoreFiles($type, true); 115 $checkInstance = new CheckAttachmentGallery($type); 116 $this->insertAttachment([ 117 'name' => 'testAttachmentWithOneFileOnDb', 118 'type' => $type, 119 'db' => true 120 ]); 121 $result = $checkInstance->analyse(); 122 123 $this->assertFalse($result['mixedLocation']); 124 $this->assertEquals(1, $result['count']); 125 $this->assertEquals(0, $result['issueCount']); 126 } 127 128 /** 129 * @dataProvider getTypes 130 * @param $type 131 */ 132 public function testAttachmentUnknownFile($type) 133 { 134 global $tikilib; 135 136 $this->configToStoreFiles($type, false); 137 $filename = md5($tikilib->now); 138 $this->createFileOnDisk($filename, 'Invalid file'); 139 140 $checkInstance = new CheckAttachmentGallery($type); 141 142 $result = $checkInstance->analyse(); 143 144 $this->assertFalse($result['usesDatabase']); 145 $this->assertFalse($result['mixedLocation']); 146 $this->assertEquals(0, $result['count'], 'Count'); // Attachment not registered in db 147 $this->assertEquals(1, $result['issueCount'], 'Issue Count'); 148 $this->assertEquals( 149 [ 150 [ 151 'name' => $filename, 152 'path' => $this->files_dir, 153 'size' => strlen('Invalid file') 154 ] 155 ], 156 $result['unknown'] 157 ); 158 } 159 160 /** 161 * @dataProvider getTypes 162 * @param $type 163 * @throws \Exception 164 */ 165 public function testAttachmentMismatchFile($type) 166 { 167 global $tikilib; 168 169 $this->configToStoreFiles($type, false); 170 171 $filename = md5($tikilib->now); 172 173 $id = $this->insertAttachment([ 174 'name' => $filename, 175 'fhash' => $filename, 176 'type' => $type, 177 'size' => 1 // the size will create the mismatch 178 ]); 179 180 $checkInstance = new CheckAttachmentGallery($type); 181 182 $result = $checkInstance->analyse(); 183 184 $this->assertFalse($result['usesDatabase']); 185 $this->assertFalse($result['mixedLocation']); 186 $this->assertEquals(1, $result['count'], 'Count'); 187 $this->assertEquals(1, $result['issueCount'], 'Issue Count'); 188 $this->assertEquals( 189 [ 190 [ 191 'name' => $filename, 192 'path' => $this->files_dir, 193 'size' => 1, 194 'id' => $id 195 ] 196 ], 197 $result['mismatch'] 198 ); 199 } 200 201 /** 202 * Test that a file that should be stored in filesystem is missing 203 * 204 * @dataProvider getTypes 205 * @param $type 206 * @throws \Exception 207 */ 208 public function testAttachmentMissingFile($type) 209 { 210 global $tikilib; 211 212 $this->configToStoreFiles($type, false); 213 214 $filename = md5($tikilib->now); 215 $id = $this->insertAttachment([ 216 'name' => $filename, 217 'fhash' => $filename, 218 'type' => $type, 219 ]); 220 221 if (file_exists($this->files_dir . $filename)) { 222 unlink($this->files_dir . $filename); 223 } 224 225 $checkInstance = new CheckAttachmentGallery($type); 226 227 $result = $checkInstance->analyse(); 228 229 $this->assertFalse($result['usesDatabase']); 230 $this->assertFalse($result['mixedLocation']); 231 $this->assertEquals(1, $result['count'], 'Count'); 232 $this->assertEquals(1, $result['issueCount'], 'Issue Count'); 233 $this->assertEquals([ 234 [ 235 'name' => $filename, 236 'path' => $this->files_dir, 237 'size' => (int)strlen($this->default_file_content), 238 'id' => $id, 239 ] 240 ], $result['missing']); 241 } 242 243 /** 244 * Configures the preferences to set the storage in the disk for a specific type 245 * @param $type 246 */ 247 protected function configToStoreFiles($type, $use_db = false) 248 { 249 global $prefs; 250 $prefs[$type . '_use_db'] = $use_db ? 'y' : 'n'; 251 $prefs[$type . '_use_dir'] = $use_db ? '' : $this->files_dir; 252 } 253 254 /** 255 * Inserts a TXT file attachment for a specific type 256 * @param $base_name 257 * @param $type 258 * @return mixed 259 * @throws \Exception 260 */ 261 protected function insertAttachment($file) 262 { 263 global $tikilib; 264 265 $id = null; 266 $base_name = $file['name']; 267 $useDB = isset($file['db']) && $file['db']; 268 269 $string = $this->default_file_content; 270 $size = isset($file['size']) ? $file['size'] : strlen($string); 271 $type = $file['type']; 272 273 $lib = $this->getLib($type); 274 $dir = $useDB ? '' : $this->files_dir; 275 $fhash = null; 276 277 if (! $useDB) { 278 $fhash = isset($file['fhash']) ? $file['fhash'] : md5($base_name . $tikilib->now); 279 $this->createFileOnDisk($fhash, $string); 280 $string = null; 281 } 282 283 switch ($type) { 284 case 'w': 285 $id = $lib->wiki_attach_file('test', $base_name, '.txt', (int)$size, $string, 0, 0, $fhash, time()); 286 break; 287 case 't': 288 $id = $lib->replace_item_attachment(null, $base_name, '.txt', (int)$size, $string, 0, 0, $fhash, '', '', 0, 0, [], []); 289 break; 290 case 'f': 291 $id = $lib->forum_attach_file(0, 0, $base_name, '.txt', (int)$size, $string, $fhash, $dir, 0); 292 break; 293 } 294 295 return $id; 296 } 297 298 /** 299 * Function to create a local file with a specific content 300 * @param $file_name 301 * @param $content 302 * @param string $extension 303 */ 304 protected function createFileOnDisk($file_name, $content) 305 { 306 $full_path = $this->files_dir . $file_name; 307 $myfile = fopen($full_path, "w") or die("Unable to open file!"); 308 fwrite($myfile, $content); 309 fclose($myfile); 310 } 311 312 /** 313 * Clears and prepares the DB to run the tests 314 * @throws \Exception 315 */ 316 protected function removeAttachmentsFromDb() 317 { 318 $types = ['f', 't', 'w']; 319 320 foreach ($types as $type) { 321 $lib = $this->getLib($type); 322 $attachments = $lib->list_all_attachements(); 323 324 foreach ($attachments['data'] as $attachment) { 325 $this->removeAttachment($type, $attachment['attId']); 326 } 327 } 328 } 329 330 /** 331 * Gets the lib related to a specific attachment type 332 * @param $type 333 * @return \WikiLib|\TrackerLib|\Comments 334 * @throws \Exception 335 */ 336 protected function getLib($type) 337 { 338 switch ($type) { 339 case 'w': 340 return TikiLib::lib('wiki'); 341 case 't': 342 return TikiLib::lib('trk'); 343 case 'f': 344 return TikiLib::lib('comments'); 345 } 346 } 347 348 /** 349 * Gets the method responsible for removing an attachment based on the type 350 * @param $type 351 * @throws \Exception 352 */ 353 protected function removeAttachment($type, $id) 354 { 355 $lib = $this->getLib($type); 356 357 switch ($type) { 358 case 'w': 359 $lib->remove_wiki_attachment($id); 360 break; 361 case 't': 362 $lib->remove_item_attachment($id); 363 break; 364 case 'f': 365 $lib->remove_thread_attachment($id); 366 break; 367 } 368 } 369 370 /** 371 * Refreshes mock directory to store files for test purposes 372 */ 373 protected function refreshDirectory() 374 { 375 $this->file_root = vfsStream::setup(uniqid('', true), null); 376 $this->files_dir = $this->file_root->url() . '/test/'; 377 mkdir($this->files_dir); 378 } 379 380 /** 381 * Data provider to test all attachment galleries 382 * 383 * @return array 384 */ 385 public function getTypes() 386 { 387 return [ 388 'forum' => ['f'], 389 'tracker' => ['t'], 390 'wiki' => ['w'], 391 ]; 392 } 393} 394