annotate core/modules/file/tests/src/Functional/FileFieldRevisionTest.php @ 5:12f9dff5fda9 tip

Update to Drupal core 8.7.1
author Chris Cannam
date Thu, 09 May 2019 15:34:47 +0100
parents a9cd425dd02b
children
rev   line source
Chris@4 1 <?php
Chris@4 2
Chris@4 3 namespace Drupal\Tests\file\Functional;
Chris@4 4
Chris@5 5 use Drupal\Core\Database\Database;
Chris@4 6 use Drupal\file\Entity\File;
Chris@4 7
Chris@4 8 /**
Chris@4 9 * Tests creating and deleting revisions with files attached.
Chris@4 10 *
Chris@4 11 * @group file
Chris@4 12 */
Chris@4 13 class FileFieldRevisionTest extends FileFieldTestBase {
Chris@4 14
Chris@4 15 /**
Chris@4 16 * Tests creating multiple revisions of a node and managing attached files.
Chris@4 17 *
Chris@4 18 * Expected behaviors:
Chris@4 19 * - Adding a new revision will make another entry in the field table, but
Chris@4 20 * the original file will not be duplicated.
Chris@4 21 * - Deleting a revision should not delete the original file if the file
Chris@4 22 * is in use by another revision.
Chris@4 23 * - When the last revision that uses a file is deleted, the original file
Chris@4 24 * should be deleted also.
Chris@4 25 */
Chris@4 26 public function testRevisions() {
Chris@4 27 // This test expects unused managed files to be marked as a temporary file
Chris@4 28 // and then deleted up by file_cron().
Chris@4 29 $this->config('file.settings')
Chris@4 30 ->set('make_unused_managed_files_temporary', TRUE)
Chris@4 31 ->save();
Chris@4 32 $node_storage = $this->container->get('entity.manager')->getStorage('node');
Chris@4 33 $type_name = 'article';
Chris@4 34 $field_name = strtolower($this->randomMachineName());
Chris@4 35 $this->createFileField($field_name, 'node', $type_name);
Chris@4 36 // Create the same fields for users.
Chris@4 37 $this->createFileField($field_name, 'user', 'user');
Chris@4 38
Chris@4 39 $test_file = $this->getTestFile('text');
Chris@4 40
Chris@4 41 // Create a new node with the uploaded file.
Chris@4 42 $nid = $this->uploadNodeFile($test_file, $field_name, $type_name);
Chris@4 43
Chris@4 44 // Check that the file exists on disk and in the database.
Chris@4 45 $node_storage->resetCache([$nid]);
Chris@4 46 $node = $node_storage->load($nid);
Chris@4 47 $node_file_r1 = File::load($node->{$field_name}->target_id);
Chris@4 48 $node_vid_r1 = $node->getRevisionId();
Chris@4 49 $this->assertFileExists($node_file_r1, 'New file saved to disk on node creation.');
Chris@4 50 $this->assertFileEntryExists($node_file_r1, 'File entry exists in database on node creation.');
Chris@4 51 $this->assertFileIsPermanent($node_file_r1, 'File is permanent.');
Chris@4 52
Chris@4 53 // Upload another file to the same node in a new revision.
Chris@4 54 $this->replaceNodeFile($test_file, $field_name, $nid);
Chris@4 55 $node_storage->resetCache([$nid]);
Chris@4 56 $node = $node_storage->load($nid);
Chris@4 57 $node_file_r2 = File::load($node->{$field_name}->target_id);
Chris@4 58 $node_vid_r2 = $node->getRevisionId();
Chris@4 59 $this->assertFileExists($node_file_r2, 'Replacement file exists on disk after creating new revision.');
Chris@4 60 $this->assertFileEntryExists($node_file_r2, 'Replacement file entry exists in database after creating new revision.');
Chris@4 61 $this->assertFileIsPermanent($node_file_r2, 'Replacement file is permanent.');
Chris@4 62
Chris@4 63 // Check that the original file is still in place on the first revision.
Chris@4 64 $node = node_revision_load($node_vid_r1);
Chris@4 65 $current_file = File::load($node->{$field_name}->target_id);
Chris@4 66 $this->assertEqual($node_file_r1->id(), $current_file->id(), 'Original file still in place after replacing file in new revision.');
Chris@4 67 $this->assertFileExists($node_file_r1, 'Original file still in place after replacing file in new revision.');
Chris@4 68 $this->assertFileEntryExists($node_file_r1, 'Original file entry still in place after replacing file in new revision');
Chris@4 69 $this->assertFileIsPermanent($node_file_r1, 'Original file is still permanent.');
Chris@4 70
Chris@4 71 // Save a new version of the node without any changes.
Chris@4 72 // Check that the file is still the same as the previous revision.
Chris@4 73 $this->drupalPostForm('node/' . $nid . '/edit', ['revision' => '1'], t('Save'));
Chris@4 74 $node_storage->resetCache([$nid]);
Chris@4 75 $node = $node_storage->load($nid);
Chris@4 76 $node_file_r3 = File::load($node->{$field_name}->target_id);
Chris@4 77 $node_vid_r3 = $node->getRevisionId();
Chris@4 78 $this->assertEqual($node_file_r2->id(), $node_file_r3->id(), 'Previous revision file still in place after creating a new revision without a new file.');
Chris@4 79 $this->assertFileIsPermanent($node_file_r3, 'New revision file is permanent.');
Chris@4 80
Chris@4 81 // Revert to the first revision and check that the original file is active.
Chris@4 82 $this->drupalPostForm('node/' . $nid . '/revisions/' . $node_vid_r1 . '/revert', [], t('Revert'));
Chris@4 83 $node_storage->resetCache([$nid]);
Chris@4 84 $node = $node_storage->load($nid);
Chris@4 85 $node_file_r4 = File::load($node->{$field_name}->target_id);
Chris@4 86 $this->assertEqual($node_file_r1->id(), $node_file_r4->id(), 'Original revision file still in place after reverting to the original revision.');
Chris@4 87 $this->assertFileIsPermanent($node_file_r4, 'Original revision file still permanent after reverting to the original revision.');
Chris@4 88
Chris@4 89 // Delete the second revision and check that the file is kept (since it is
Chris@4 90 // still being used by the third revision).
Chris@4 91 $this->drupalPostForm('node/' . $nid . '/revisions/' . $node_vid_r2 . '/delete', [], t('Delete'));
Chris@4 92 $this->assertFileExists($node_file_r3, 'Second file is still available after deleting second revision, since it is being used by the third revision.');
Chris@4 93 $this->assertFileEntryExists($node_file_r3, 'Second file entry is still available after deleting second revision, since it is being used by the third revision.');
Chris@4 94 $this->assertFileIsPermanent($node_file_r3, 'Second file entry is still permanent after deleting second revision, since it is being used by the third revision.');
Chris@4 95
Chris@4 96 // Attach the second file to a user.
Chris@4 97 $user = $this->drupalCreateUser();
Chris@4 98 $user->$field_name->target_id = $node_file_r3->id();
Chris@4 99 $user->$field_name->display = 1;
Chris@4 100 $user->save();
Chris@4 101 $this->drupalGet('user/' . $user->id() . '/edit');
Chris@4 102
Chris@4 103 // Delete the third revision and check that the file is not deleted yet.
Chris@4 104 $this->drupalPostForm('node/' . $nid . '/revisions/' . $node_vid_r3 . '/delete', [], t('Delete'));
Chris@4 105 $this->assertFileExists($node_file_r3, 'Second file is still available after deleting third revision, since it is being used by the user.');
Chris@4 106 $this->assertFileEntryExists($node_file_r3, 'Second file entry is still available after deleting third revision, since it is being used by the user.');
Chris@4 107 $this->assertFileIsPermanent($node_file_r3, 'Second file entry is still permanent after deleting third revision, since it is being used by the user.');
Chris@4 108
Chris@4 109 // Delete the user and check that the file is also deleted.
Chris@4 110 $user->delete();
Chris@4 111 // TODO: This seems like a bug in File API. Clearing the stat cache should
Chris@4 112 // not be necessary here. The file really is deleted, but stream wrappers
Chris@4 113 // doesn't seem to think so unless we clear the PHP file stat() cache.
Chris@4 114 clearstatcache($node_file_r1->getFileUri());
Chris@4 115 clearstatcache($node_file_r2->getFileUri());
Chris@4 116 clearstatcache($node_file_r3->getFileUri());
Chris@4 117 clearstatcache($node_file_r4->getFileUri());
Chris@4 118
Chris@4 119 // Call file_cron() to clean up the file. Make sure the changed timestamp
Chris@4 120 // of the file is older than the system.file.temporary_maximum_age
Chris@5 121 // configuration value. We use an UPDATE statement because using the API
Chris@5 122 // would set the timestamp.
Chris@5 123 $connection = Database::getConnection();
Chris@5 124 $connection->update('file_managed')
Chris@4 125 ->fields([
Chris@4 126 'changed' => REQUEST_TIME - ($this->config('system.file')->get('temporary_maximum_age') + 1),
Chris@4 127 ])
Chris@4 128 ->condition('fid', $node_file_r3->id())
Chris@4 129 ->execute();
Chris@4 130 \Drupal::service('cron')->run();
Chris@4 131
Chris@4 132 $this->assertFileNotExists($node_file_r3, 'Second file is now deleted after deleting third revision, since it is no longer being used by any other nodes.');
Chris@4 133 $this->assertFileEntryNotExists($node_file_r3, 'Second file entry is now deleted after deleting third revision, since it is no longer being used by any other nodes.');
Chris@4 134
Chris@4 135 // Delete the entire node and check that the original file is deleted.
Chris@4 136 $this->drupalPostForm('node/' . $nid . '/delete', [], t('Delete'));
Chris@4 137 // Call file_cron() to clean up the file. Make sure the changed timestamp
Chris@4 138 // of the file is older than the system.file.temporary_maximum_age
Chris@5 139 // configuration value. We use an UPDATE statement because using the API
Chris@5 140 // would set the timestamp.
Chris@5 141 $connection->update('file_managed')
Chris@4 142 ->fields([
Chris@4 143 'changed' => REQUEST_TIME - ($this->config('system.file')->get('temporary_maximum_age') + 1),
Chris@4 144 ])
Chris@4 145 ->condition('fid', $node_file_r1->id())
Chris@4 146 ->execute();
Chris@4 147 \Drupal::service('cron')->run();
Chris@4 148 $this->assertFileNotExists($node_file_r1, 'Original file is deleted after deleting the entire node with two revisions remaining.');
Chris@4 149 $this->assertFileEntryNotExists($node_file_r1, 'Original file entry is deleted after deleting the entire node with two revisions remaining.');
Chris@4 150 }
Chris@4 151
Chris@4 152 }