filetransfer.test 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. <?php
  2. class FileTranferTest extends DrupalWebTestCase {
  3. protected $hostname = 'localhost';
  4. protected $username = 'drupal';
  5. protected $password = 'password';
  6. protected $port = '42';
  7. protected $testConnection;
  8. public static function getInfo() {
  9. return array(
  10. 'name' => 'FileTransfer unit tests',
  11. 'description' => 'Test that the jail is respected and that protocols using recursive file move operations work.',
  12. 'group' => 'System'
  13. );
  14. }
  15. function setUp() {
  16. parent::setUp();
  17. $this->testConnection = TestFileTransfer::factory(DRUPAL_ROOT, array('hostname' => $this->hostname, 'username' => $this->username, 'password' => $this->password, 'port' => $this->port));
  18. }
  19. function _getFakeModuleFiles() {
  20. $files = array(
  21. 'fake.module',
  22. 'fake.info',
  23. 'theme' => array(
  24. 'fake.tpl.php'
  25. ),
  26. 'inc' => array(
  27. 'fake.inc'
  28. )
  29. );
  30. return $files;
  31. }
  32. function _buildFakeModule() {
  33. $location = 'temporary://fake';
  34. if (is_dir($location)) {
  35. $ret = 0;
  36. $output = array();
  37. exec('rm -Rf ' . escapeshellarg($location), $output, $ret);
  38. if ($ret != 0) {
  39. throw new Exception('Error removing fake module directory.');
  40. }
  41. }
  42. $files = $this->_getFakeModuleFiles();
  43. $this->_writeDirectory($location, $files);
  44. return $location;
  45. }
  46. function _writeDirectory($base, $files = array()) {
  47. mkdir($base);
  48. foreach ($files as $key => $file) {
  49. if (is_array($file)) {
  50. $this->_writeDirectory($base . DIRECTORY_SEPARATOR . $key, $file);
  51. }
  52. else {
  53. //just write the filename into the file
  54. file_put_contents($base . DIRECTORY_SEPARATOR . $file, $file);
  55. }
  56. }
  57. }
  58. function testJail() {
  59. $source = $this->_buildFakeModule();
  60. // This convoluted piece of code is here because our testing framework does
  61. // not support expecting exceptions.
  62. $gotit = FALSE;
  63. try {
  64. $this->testConnection->copyDirectory($source, '/tmp');
  65. }
  66. catch (FileTransferException $e) {
  67. $gotit = TRUE;
  68. }
  69. $this->assertTrue($gotit, 'Was not able to copy a directory outside of the jailed area.');
  70. $gotit = TRUE;
  71. try {
  72. $this->testConnection->copyDirectory($source, DRUPAL_ROOT . '/'. variable_get('file_public_path', conf_path() . '/files'));
  73. }
  74. catch (FileTransferException $e) {
  75. $gotit = FALSE;
  76. }
  77. $this->assertTrue($gotit, 'Was able to copy a directory inside of the jailed area');
  78. }
  79. }
  80. /**
  81. * Mock FileTransfer object for test case.
  82. */
  83. class TestFileTransfer extends FileTransfer {
  84. protected $host = NULL;
  85. protected $username = NULL;
  86. protected $password = NULL;
  87. protected $port = NULL;
  88. /**
  89. * This is for testing the CopyRecursive logic.
  90. */
  91. public $shouldIsDirectoryReturnTrue = FALSE;
  92. function __construct($jail, $username, $password, $hostname = 'localhost', $port = 9999) {
  93. parent::__construct($jail, $username, $password, $hostname, $port);
  94. }
  95. static function factory($jail, $settings) {
  96. return new TestFileTransfer($jail, $settings['username'], $settings['password'], $settings['hostname'], $settings['port']);
  97. }
  98. function connect() {
  99. $parts = explode(':', $this->hostname);
  100. $port = (count($parts) == 2) ? $parts[1] : $this->port;
  101. $this->connection = new MockTestConnection();
  102. $this->connection->connectionString = 'test://' . urlencode((string) $this->username) . ':' . urlencode((string) $this->password) . "@$this->host:$this->port/";
  103. }
  104. function copyFileJailed($source, $destination) {
  105. $this->connection->run("copyFile $source $destination");
  106. }
  107. protected function removeDirectoryJailed($directory) {
  108. $this->connection->run("rmdir $directory");
  109. }
  110. function createDirectoryJailed($directory) {
  111. $this->connection->run("mkdir $directory");
  112. }
  113. function removeFileJailed($destination) {
  114. if (!ftp_delete($this->connection, $item)) {
  115. throw new FileTransferException('Unable to remove to file @file.', NULL, array('@file' => $item));
  116. }
  117. }
  118. function isDirectory($path) {
  119. return $this->shouldIsDirectoryReturnTrue;
  120. }
  121. function isFile($path) {
  122. return FALSE;
  123. }
  124. function chmodJailed($path, $mode, $recursive) {
  125. return;
  126. }
  127. }
  128. /**
  129. * Mock connection object for test case.
  130. */
  131. class MockTestConnection {
  132. var $commandsRun = array();
  133. var $connectionString;
  134. function run($cmd) {
  135. $this->commandsRun[] = $cmd;
  136. }
  137. function flushCommands() {
  138. $out = $this->commandsRun;
  139. $this->commandsRun = array();
  140. return $out;
  141. }
  142. }