You are here

s3fs.test in S3 File System 7

Same filename and directory in other branches
  1. 7.3 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')) {
  $link = l(t('SimpleTest Clone'), 'https://drupal.org/project/simpletest_clone');
  $msg = "S3 File System's tests require the !simpletest_clone module. You will not see this message again until you clear the cache.";
  drupal_set_message(t($msg, array(
    '!link' => $link,
  )), 'warning');
  watchdog('S3 File System', $msg, array(
    '!simpletest_clone' => $link,
  ), WATCHDOG_WARNING);
}
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 {

    /**
     * These should be edited to match your site's actual setup.
     */

    // WARNING: DO NOT SET THIS TO YOUR SITE'S REAL BUCKET.
    // These tests will erase the ENTIRE CONTENTS of the bucket.
    protected $s3_bucket = 's3fs-testing-bucket';
    protected $s3_region = 'us-east-1';

    /**
     * State variables.
     */
    protected $bucket_not_found = FALSE;
    protected $remote_tests_folder = '_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');
      variable_set('s3fs_bucket', $this->s3_bucket);
      variable_set('s3fs_region', $this->s3_region);

      // Empty out the bucket before the test, to prevent unexpected errors.
      $this->s3 = _s3fs_get_amazons3_client(_s3fs_get_config());
      try {
        $deleted_files_count = $this->s3
          ->clearBucket($this->s3_bucket);
        debug("Deleted {$deleted_files_count} file(s) from S3 to prepare for the test.");
      } catch (Aws\S3\Exception\NoSuchBucketException $e) {
        $this->bucket_not_found = TRUE;
      }
      global $_s3fs_debug, $_s3fs_debug_internal;
      $_s3fs_debug = TRUE;

      // Normally we want to hide the debug log messages for the wrapper's
      // internal functons. But setting this to TRUE will unhide them.
      $_s3fs_debug_internal = FALSE;
    }

    /**
     * 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->s3_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 getExternalUri().');
      $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->s3_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_path1 = "{$this->remote_tests_folder}/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.
      // If you're using Xdebug and the Eclipse IDE, the XDEBUG_SESSION_START
      // query arg will make this drupalGet() call debuggable.
      $derivative = $this
        ->drupalGet(image_style_url('thumbnail', $img_uri1), array(
        'query' => array(
          'XDEBUG_SESSION_START' => 'ECLIPSE_DPGP',
        ),
      ));
      $this
        ->assertTrue(imagecreatefromstring($derivative), 'The returned derivative is a valid image.');
    }

    /**
     * Test the full and partial 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->s3_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 wont cache them.
      $filenames = array(
        'files/test2.txt',
        'parts/test3.txt',
        'test.txt',
      );
      foreach ($filenames as $filename) {
        $this->s3
          ->upload($this->s3_bucket, $filename, 'testtesttest', 'public-read');
      }

      // Run a regular cache refresh, being sure to use no prefix.
      $config = _s3fs_get_config();
      $config['prefix'] = '';
      _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 partial refresh on only one folder.
      $delete_query = db_delete('s3fs_file')
        ->execute();
      $config['prefix'] = '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://parts/test3.txt', 'That file was the one in the "parts" folder.');
    }

  }

  // END S3fsTests class
}