You are here

s3fs.test in S3 File System 7.3

Same filename and directory in other branches
  1. 7 tests/s3fs.test
  2. 7.2 tests/s3fs.test

File

tests/s3fs.test
View source
<?php

// Only define the S3fsTests class if the SimpleTest Clone module is installed.
if (!module_exists('simpletest_clone')) {
  $t = get_t();
  $link = 'https://www.drupal.org/project/simpletest_clone';
  drupal_set_message($t('S3 File System tests require the <a href="!link">SimpleTest Clone</a> module. You will not see this message again until you clear the cache.', array(
    '!link' => $link,
  )), 'warning');
  watchdog('s3fs', 'S3 File System tests require the SimpleTest Clone module. You will not see this message again until you clear the cache.', array(), WATCHDOG_WARNING, l("SimpleTest Clone", $link, array(
    'absolute' => TRUE,
  )));
}
else {
  module_load_include('php', 'simpletest_clone', 'simpletest_clone_test_case');

  // These tests require SimpleTestCloneTestcase because the AWS credentials are
  // configured in settings.php, which apparently doesn't get executed during a
  // DrupalWebTestcase.
  class S3fsTests extends SimpleTestCloneTestcase {

    /**
     * State variables.
     */
    protected $bucket_not_found = FALSE;
    protected $remote_tests_folder = '_s3fs_tests';
    protected $remote_tests_folder_key = '_s3fs_tests';
    protected $remote_tests_folder_uri = 's3://_s3fs_tests';
    public static function getInfo() {
      return array(
        'name' => 'S3 File System Tests',
        'description' => 'Ensure that the remote file system functionality provided by S3 File System works correctly.',
        'group' => 'S3 File System',
      );
    }
    function setUp() {
      parent::setUp('s3fs');

      // Empty out the bucket before the test, to prevent unexpected errors.
      $this->config = _s3fs_get_config();
      $this->s3 = _s3fs_get_amazons3_client($this->config);
      if (!empty($this->config['root_folder'])) {
        $this->remote_tests_folder_key = "{$this->config['root_folder']}/{$this->remote_tests_folder}";
      }

      // Adding this to ensure it's set.
      $this->public_files_directory = variable_get('file_public_path');

      // Prevent issues with derivative tokens during test.
      variable_set('image_allow_insecure_derivatives', TRUE);
      $this->bucket_not_found = !$this->s3
        ->doesBucketExist($this->config['bucket']);
      if (!$this->bucket_not_found) {
        $this->s3
          ->deleteMatchingObjects($this->config['bucket'], $this->remote_tests_folder_key);
        debug("Deleted file(s) from S3 test folder to prepare for the test.");
      }
    }

    /**
     * Coverage test for the stream wrapper.
     */
    public function testStreamWrapperCoverage() {

      // This is here, rather than the setUp() function, because we want the
      // test to immediately exit if this happens.
      if ($this->bucket_not_found) {
        $this
          ->fail("The '{$this->config['bucket']}' bucket does not exist in the '{$this->s3_region}' region on your AWS account.\n          Either edit the protected properties of the S3fsTests class, or create a bucket called 's3fs-testing-bucket' in the 'us-east-1' region.");
        return;
      }
      $test_uri1 = "{$this->remote_tests_folder_uri}/test_file.txt";
      $test_uri2 = "{$this->remote_tests_folder_uri}/test_file2.txt";
      $this
        ->assertTrue(file_stream_wrapper_valid_scheme('s3'), '"s3" is a valid stream wrapper scheme.');
      $this
        ->assertEqual(file_stream_wrapper_get_class('s3'), 'S3fsStreamWrapper', 'URIs with scheme "s3" should be handled by S3fsStreamWrapper.');

      // The test.txt file is enough data to force multiple calls to write_stream().
      $file_contents = file_get_contents(drupal_get_path('module', 's3fs') . '/tests/test.txt');
      $this
        ->assertTrue(drupal_mkdir($this->remote_tests_folder_uri), 'Exercised mkdir to create the testing directory (in the DB).');
      $this
        ->assertTrue(is_dir($this->remote_tests_folder_uri), 'Make sure the folder we just created correctly reports that it is a folder.');
      debug("Exercising file upload functionality.");
      $start_time = time();
      $s3_file = file_save_data($file_contents, $test_uri1);
      $end_time = time();
      $total = $end_time - $start_time;
      debug("Upload time: {$total} seconds");
      $this
        ->assertTrue(file_valid_uri($s3_file->uri), "Uploaded the first test file, {$test_uri1}.");
      debug("Exercising file copy functionality.");
      $s3_file2 = file_copy($s3_file, $test_uri2);
      $this
        ->assertNotIdentical($s3_file2, FALSE, "Copied the the first test file to {$test_uri2}.");
      debug('Exercising the dir_*() functions.');
      $files = file_scan_directory($this->remote_tests_folder_uri, '#.*#');
      $this
        ->assertTrue(isset($files[$test_uri1]), 'The first test file is in the tests directory.');
      $this
        ->assertTrue(isset($files[$test_uri2]), 'The second test file is in the tests directory.');
      $this
        ->assertEqual(count($files), 2, "There are exactly two files in the tests directory.");
      debug('Exercising getExternalUrl().');
      $url = file_create_url($test_uri1);
      $this
        ->assertNotIdentical($url, FALSE, 'file_create_url() succeeded.');
      debug('Exercising unlink().');
      $this
        ->assertIdentical(file_delete($s3_file), TRUE, "Deleted the first test file.");
      $this
        ->assertIdentical(file_exists($test_uri1), FALSE, 'The wrapper reports that the first test file no longer exists.');
      debug('Exercising rename().');
      $this
        ->assertTrue(rename($test_uri2, $test_uri1), "Renamed the second test file to the newly-vacated URI of {$test_uri1}.");
      $s3_file2->uri = $test_uri1;
      debug('Exercising rmdir().');
      $this
        ->assertFalse(drupal_rmdir($this->remote_tests_folder_uri), 'rmdir() did not delete the tests folder because it is not empty.');
      $this
        ->assertTrue(file_delete($s3_file2), 'Deleted the last test file.');
      $this
        ->assertTrue(drupal_rmdir($this->remote_tests_folder_uri), 'Deleted the tests folder.');
      $this
        ->assertFalse(is_dir($this->remote_tests_folder_uri), 'The wrapper reports that the tests folder is gone.');
    }

    /**
     * Test the image derivative functionality.
     */
    public function testImageDerivatives() {

      // This is here, rather than the setUp() function, because we want the
      // test to immediately exit if this happens.
      if ($this->bucket_not_found) {
        $this
          ->fail("The '{$this->config['bucket']}' bucket does not exist in the '{$this->s3_region}' region on your AWS account.\n          Either edit the protected properties of the S3fsTests class, or create a bucket called 's3fs-testing-bucket' in the 'us-east-1' region.");
        return;
      }
      $img_uri1 = "{$this->remote_tests_folder_uri}/test.png";
      $img_localpath = drupal_get_path('module', 's3fs') . '/tests/test.png';

      // Upload the test image.
      $this
        ->assertTrue(drupal_mkdir($this->remote_tests_folder_uri), 'Created the testing directory in the DB.');
      $img_data = file_get_contents($img_localpath);
      $img_file = file_save_data($img_data, $img_uri1);
      $this
        ->assertTrue($img_file, "Copied the the test image to {$img_uri1}.");

      // Request a derivative.
      // Parse query parameters to ensure they get passed.
      $style_url_parsed = drupal_parse_url(image_style_url('thumbnail', $img_uri1));
      $derivative = $this
        ->drupalGet($style_url_parsed['path'], array(
        'query' => $style_url_parsed['query'],
      ));
      $this
        ->assertTrue(imagecreatefromstring($derivative), 'The returned derivative is a valid image.');
    }

    /**
     * Test the cache refresh.
     */
    public function testCacheRefresh() {

      // This is here, rather than the setUp() function, because we want the
      // test to immediately exit if this happens.
      if ($this->bucket_not_found) {
        $this
          ->fail("The '{$this->config['bucket']}' bucket does not exist in the '{$this->s3_region}' region on your AWS account.\n          Either edit the protected properties of the S3fsTests class, or create a bucket called 's3fs-testing-bucket' in the 'us-east-1' region.");
        return;
      }

      // Add several files to the bucket using the AWS SDK directly, so that
      // s3fs won't cache them.
      $filenames = array(
        'files/test2.txt',
        'parts/test3.txt',
        'test.txt',
      );
      foreach ($filenames as $filename) {
        $filename = $this->remote_tests_folder_key . '/' . $filename;
        $this->s3
          ->putObject(array(
          'Bucket' => $this->config['bucket'],
          'Key' => $filename,
          'ACL' => 'public-read',
        ));
      }
      $config = _s3fs_get_config();

      // Set the current test folder as the root prefix.
      $config['root_folder'] = $this->remote_tests_folder_key;
      _s3fs_refresh_cache($config);

      // Query the DB to confirm that all the new files are cached.
      $result = db_select('s3fs_file', 's')
        ->fields('s')
        ->condition('dir', 0, '=')
        ->execute();
      $cached_files = array();
      foreach ($result as $record) {
        $cached_files[] = str_replace('s3://', '', $record->uri);
      }
      $this
        ->assertEqual($filenames, $cached_files, 'The test files were all cached.');

      // Flush the cache, then do a refresh using the root_folder setting.
      // Only the file in the root folder (test3.txt) should become cached.
      $delete_query = db_delete('s3fs_file')
        ->execute();
      $config['root_folder'] = $this->remote_tests_folder_key . '/parts';
      _s3fs_refresh_cache($config);

      // Confirm that only the file in the "parts" folder was cached.
      $records = db_select('s3fs_file', 's')
        ->fields('s')
        ->condition('dir', 0, '=')
        ->execute()
        ->fetchAll();
      $this
        ->assertEqual(count($records), 1, 'There was only one file in the partially rereshed cache.');
      $this
        ->assertEqual($records[0]->uri, 's3://test3.txt', 'That file was the one in the "parts" folder, which is now the root folder, so "parts" is not in the URI.');
    }

    /**
     * Clean up S3 folder.
     */
    public function tearDown() {
      $this->s3
        ->deleteMatchingObjects($this->config['bucket'], $this->remote_tests_folder_key);
      parent::tearDown();
    }

  }

  // END S3fsTests class
}