3 namespace Drupal\Tests\migrate\Kernel\process;
5 use Drupal\Core\StreamWrapper\StreamWrapperInterface;
6 use Drupal\KernelTests\Core\File\FileTestBase;
7 use Drupal\migrate\MigrateException;
8 use Drupal\migrate\Plugin\migrate\process\FileCopy;
9 use Drupal\migrate\MigrateExecutableInterface;
10 use Drupal\migrate\Plugin\MigrateProcessInterface;
11 use Drupal\migrate\Row;
12 use GuzzleHttp\Client;
15 * Tests the file_copy process plugin.
17 * @coversDefaultClass \Drupal\migrate\Plugin\migrate\process\FileCopy
21 class FileCopyTest extends FileTestBase {
26 public static $modules = ['migrate', 'system'];
29 * The file system service.
31 * @var \Drupal\Core\File\FileSystemInterface
33 protected $fileSystem;
38 protected function setUp() {
40 $this->fileSystem = $this->container->get('file_system');
41 $this->container->get('stream_wrapper_manager')->registerWrapper('temporary', 'Drupal\Core\StreamWrapper\TemporaryStream', StreamWrapperInterface::LOCAL_NORMAL);
45 * Test successful imports/copies.
47 public function testSuccessfulCopies() {
48 $file = $this->createUri(NULL, NULL, 'temporary');
49 $file_absolute = $this->fileSystem->realpath($file);
51 // Test a local to local copy.
53 $this->root . '/core/modules/simpletest/files/image-test.jpg',
56 // Test a temporary file using an absolute path.
59 'temporary://test.jpg',
61 // Test a temporary file using a relative path.
64 'temporary://core/modules/simpletest/files/test.jpg',
67 foreach ($data_sets as $data) {
68 list($source_path, $destination_path) = $data;
69 $actual_destination = $this->doTransform($source_path, $destination_path);
70 $message = sprintf('File %s exists', $destination_path);
71 $this->assertFileExists($destination_path, $message);
72 // Make sure we didn't accidentally do a move.
73 $this->assertFileExists($source_path, $message);
74 $this->assertSame($actual_destination, $destination_path, 'The import returned the copied filename.');
79 * Test successful file reuse.
81 * @dataProvider providerSuccessfulReuse
83 * @param string $source_path
84 * Source path to copy from.
85 * @param string $destination_path
86 * The destination path to copy to.
88 public function testSuccessfulReuse($source_path, $destination_path) {
89 $file_reuse = $this->doTransform($source_path, $destination_path);
90 clearstatcache(TRUE, $destination_path);
92 $timestamp = (new \SplFileInfo($file_reuse))->getMTime();
93 $this->assertInternalType('int', $timestamp);
95 // We need to make sure the modified timestamp on the file is sooner than
96 // the attempted migration.
98 $configuration = ['file_exists' => 'use existing'];
99 $this->doTransform($source_path, $destination_path, $configuration);
100 clearstatcache(TRUE, $destination_path);
101 $modified_timestamp = (new \SplFileInfo($destination_path))->getMTime();
102 $this->assertEquals($timestamp, $modified_timestamp);
104 $this->doTransform($source_path, $destination_path);
105 clearstatcache(TRUE, $destination_path);
106 $modified_timestamp = (new \SplFileInfo($destination_path))->getMTime();
107 $this->assertGreaterThan($timestamp, $modified_timestamp);
111 * Provides the source and destination path files.
113 public function providerSuccessfulReuse() {
116 'local_source_path' => static::getDrupalRoot() . '/core/modules/simpletest/files/image-test.jpg',
117 'local_destination_path' => 'public://file1.jpg',
120 'remote_source_path' => 'https://www.drupal.org/favicon.ico',
121 'remote_destination_path' => 'public://file2.jpg',
127 * Test successful moves.
129 public function testSuccessfulMoves() {
130 $file_1 = $this->createUri(NULL, NULL, 'temporary');
131 $file_1_absolute = $this->fileSystem->realpath($file_1);
132 $file_2 = $this->createUri(NULL, NULL, 'temporary');
133 $file_2_absolute = $this->fileSystem->realpath($file_2);
134 $local_file = $this->createUri(NULL, NULL, 'public');
136 // Test a local to local copy.
139 'public://file1.jpg',
141 // Test a temporary file using an absolute path.
144 'temporary://test.jpg',
146 // Test a temporary file using a relative path.
149 'temporary://core/modules/simpletest/files/test.jpg',
152 foreach ($data_sets as $data) {
153 list($source_path, $destination_path) = $data;
154 $actual_destination = $this->doTransform($source_path, $destination_path, ['move' => TRUE]);
155 $message = sprintf('File %s exists', $destination_path);
156 $this->assertFileExists($destination_path, $message);
157 $message = sprintf('File %s does not exist', $source_path);
158 $this->assertFileNotExists($source_path, $message);
159 $this->assertSame($actual_destination, $destination_path, 'The importer returned the moved filename.');
164 * Test that non-existent files throw an exception.
166 public function testNonExistentSourceFile() {
167 $source = '/non/existent/file';
168 $this->setExpectedException(MigrateException::class, "File '/non/existent/file' does not exist");
169 $this->doTransform($source, 'public://wontmatter.jpg');
173 * Tests that non-writable destination throw an exception.
175 * @covers ::transform
177 public function testNonWritableDestination() {
178 $source = $this->createUri('file.txt', NULL, 'temporary');
180 // Create the parent location.
181 $this->createDirectory('public://dir');
183 // Copy the file under public://dir/subdir1/.
184 $this->doTransform($source, 'public://dir/subdir1/file.txt');
186 // Check that 'subdir1' was created and the file was successfully migrated.
187 $this->assertFileExists('public://dir/subdir1/file.txt');
189 // Remove all permissions from public://dir to trigger a failure when
190 // trying to create a subdirectory 'subdir2' inside public://dir.
191 $this->fileSystem->chmod('public://dir', 0);
193 // Check that the proper exception is raised.
194 $this->setExpectedException(MigrateException::class, "Could not create or write to directory 'public://dir/subdir2'");
195 $this->doTransform($source, 'public://dir/subdir2/file.txt');
199 * Test the 'rename' overwrite mode.
201 public function testRenameFile() {
202 $source = $this->createUri(NULL, NULL, 'temporary');
203 $destination = $this->createUri('foo.txt', NULL, 'public');
204 $expected_destination = 'public://foo_0.txt';
205 $actual_destination = $this->doTransform($source, $destination, ['file_exists' => 'rename']);
206 $this->assertFileExists($expected_destination, 'File was renamed on import');
207 $this->assertSame($actual_destination, $expected_destination, 'The importer returned the renamed filename.');
211 * Tests that remote URIs are delegated to the download plugin.
213 public function testDownloadRemoteUri() {
214 $download_plugin = $this->getMock(MigrateProcessInterface::class);
215 $download_plugin->expects($this->once())->method('transform');
217 $plugin = new FileCopy(
219 $this->randomMachineName(),
221 $this->container->get('stream_wrapper_manager'),
222 $this->container->get('file_system'),
227 ['http://drupal.org/favicon.ico', '/destination/path'],
228 $this->getMock(MigrateExecutableInterface::class),
230 $this->randomMachineName()
235 * Do an import using the destination.
237 * @param string $source_path
238 * Source path to copy from.
239 * @param string $destination_path
240 * The destination path to copy to.
241 * @param array $configuration
242 * Process plugin configuration settings.
245 * The URI of the copied file.
247 protected function doTransform($source_path, $destination_path, $configuration = []) {
248 // Prepare a mock HTTP client.
249 $this->container->set('http_client', $this->createMock(Client::class));
251 $plugin = FileCopy::create($this->container, $configuration, 'file_copy', []);
252 $executable = $this->prophesize(MigrateExecutableInterface::class)->reveal();
253 $row = new Row([], []);
255 return $plugin->transform([$source_path, $destination_path], $executable, $row, 'foobaz');