2012-03-05 10:26:07 +00:00
< ? php
/*
* This file is part of Composer .
*
* ( c ) Nils Adermann < naderman @ naderman . de >
* Jordi Boggiano < j . boggiano @ seld . be >
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
namespace Composer\Test\Util ;
use Composer\Util\RemoteFilesystem ;
2017-11-04 14:52:13 +00:00
use PHPUnit\Framework\TestCase ;
2012-03-05 10:26:07 +00:00
2017-11-04 14:52:13 +00:00
class RemoteFilesystemTest extends TestCase
2012-03-05 10:26:07 +00:00
{
2018-11-14 16:54:19 +00:00
private function getConfigMock ()
{
$config = $this -> getMockBuilder ( 'Composer\Config' ) -> getMock ();
$config -> expects ( $this -> any ())
-> method ( 'get' )
-> will ( $this -> returnCallback ( function ( $key ) {
if ( $key === 'github-domains' || $key === 'gitlab-domains' ) {
return array ();
}
}));
return $config ;
}
2012-03-05 10:26:07 +00:00
public function testGetOptionsForUrl ()
{
2018-04-12 08:24:56 +00:00
$io = $this -> getMockBuilder ( 'Composer\IO\IOInterface' ) -> getMock ();
2012-03-05 10:26:07 +00:00
$io
-> expects ( $this -> once ())
2012-11-07 12:33:50 +00:00
-> method ( 'hasAuthentication' )
2012-03-05 10:26:07 +00:00
-> will ( $this -> returnValue ( false ))
;
2012-10-18 16:43:31 +00:00
$res = $this -> callGetOptionsForUrl ( $io , array ( 'http://example.org' , array ()));
2012-10-19 10:25:53 +00:00
$this -> assertTrue ( isset ( $res [ 'http' ][ 'header' ]) && is_array ( $res [ 'http' ][ 'header' ]), 'getOptions must return an array with headers' );
2012-03-05 10:26:07 +00:00
}
public function testGetOptionsForUrlWithAuthorization ()
{
2018-04-12 08:24:56 +00:00
$io = $this -> getMockBuilder ( 'Composer\IO\IOInterface' ) -> getMock ();
2012-03-05 10:26:07 +00:00
$io
-> expects ( $this -> once ())
2012-11-07 12:33:50 +00:00
-> method ( 'hasAuthentication' )
2012-03-05 10:26:07 +00:00
-> will ( $this -> returnValue ( true ))
;
$io
-> expects ( $this -> once ())
2012-11-07 12:33:50 +00:00
-> method ( 'getAuthentication' )
2012-03-05 10:26:07 +00:00
-> will ( $this -> returnValue ( array ( 'username' => 'login' , 'password' => 'password' )))
;
2012-10-18 16:43:31 +00:00
$options = $this -> callGetOptionsForUrl ( $io , array ( 'http://example.org' , array ()));
2012-10-19 10:25:53 +00:00
$found = false ;
foreach ( $options [ 'http' ][ 'header' ] as $header ) {
if ( 0 === strpos ( $header , 'Authorization: Basic' )) {
$found = true ;
}
}
$this -> assertTrue ( $found , 'getOptions must have an Authorization header' );
2012-03-05 10:26:07 +00:00
}
2012-10-03 13:09:47 +00:00
public function testGetOptionsForUrlWithStreamOptions ()
{
2018-04-12 08:24:56 +00:00
$io = $this -> getMockBuilder ( 'Composer\IO\IOInterface' ) -> getMock ();
2012-10-03 13:09:47 +00:00
$io
-> expects ( $this -> once ())
2012-11-07 12:33:50 +00:00
-> method ( 'hasAuthentication' )
2012-10-03 13:09:47 +00:00
-> will ( $this -> returnValue ( true ))
;
$streamOptions = array ( 'ssl' => array (
'allow_self_signed' => true ,
));
2012-10-18 16:43:31 +00:00
$res = $this -> callGetOptionsForUrl ( $io , array ( 'https://example.org' , array ()), $streamOptions );
2012-10-03 13:09:47 +00:00
$this -> assertTrue ( isset ( $res [ 'ssl' ]) && isset ( $res [ 'ssl' ][ 'allow_self_signed' ]) && true === $res [ 'ssl' ][ 'allow_self_signed' ], 'getOptions must return an array with a allow_self_signed set to true' );
}
2012-10-18 16:43:31 +00:00
public function testGetOptionsForUrlWithCallOptionsKeepsHeader ()
{
2018-04-12 08:24:56 +00:00
$io = $this -> getMockBuilder ( 'Composer\IO\IOInterface' ) -> getMock ();
2012-10-18 16:43:31 +00:00
$io
-> expects ( $this -> once ())
2012-11-07 12:33:50 +00:00
-> method ( 'hasAuthentication' )
2012-10-18 16:43:31 +00:00
-> will ( $this -> returnValue ( true ))
;
$streamOptions = array ( 'http' => array (
'header' => 'Foo: bar' ,
));
$res = $this -> callGetOptionsForUrl ( $io , array ( 'https://example.org' , $streamOptions ));
$this -> assertTrue ( isset ( $res [ 'http' ][ 'header' ]), 'getOptions must return an array with a http.header key' );
2012-10-19 10:25:53 +00:00
$found = false ;
foreach ( $res [ 'http' ][ 'header' ] as $header ) {
if ( $header === 'Foo: bar' ) {
$found = true ;
}
}
$this -> assertTrue ( $found , 'getOptions must have a Foo: bar header' );
$this -> assertGreaterThan ( 1 , count ( $res [ 'http' ][ 'header' ]));
2012-10-18 16:43:31 +00:00
}
2012-03-05 10:26:07 +00:00
public function testCallbackGetFileSize ()
{
2018-11-14 16:54:19 +00:00
$fs = new RemoteFilesystem ( $this -> getMockBuilder ( 'Composer\IO\IOInterface' ) -> getMock (), $this -> getConfigMock ());
2012-03-05 10:26:07 +00:00
$this -> callCallbackGet ( $fs , STREAM_NOTIFY_FILE_SIZE_IS , 0 , '' , 0 , 0 , 20 );
$this -> assertAttributeEquals ( 20 , 'bytesMax' , $fs );
}
public function testCallbackGetNotifyProgress ()
{
2018-04-12 08:24:56 +00:00
$io = $this -> getMockBuilder ( 'Composer\IO\IOInterface' ) -> getMock ();
2012-03-05 10:26:07 +00:00
$io
-> expects ( $this -> once ())
2015-02-18 09:04:39 +00:00
-> method ( 'overwriteError' )
2012-03-05 10:26:07 +00:00
;
2018-11-14 16:54:19 +00:00
$fs = new RemoteFilesystem ( $io , $this -> getConfigMock ());
2012-03-05 10:26:07 +00:00
$this -> setAttribute ( $fs , 'bytesMax' , 20 );
$this -> setAttribute ( $fs , 'progress' , true );
$this -> callCallbackGet ( $fs , STREAM_NOTIFY_PROGRESS , 0 , '' , 0 , 10 , 20 );
$this -> assertAttributeEquals ( 50 , 'lastProgress' , $fs );
}
2014-02-26 15:01:31 +00:00
public function testCallbackGetPassesThrough404 ()
2012-03-05 10:26:07 +00:00
{
2018-11-14 16:54:19 +00:00
$fs = new RemoteFilesystem ( $this -> getMockBuilder ( 'Composer\IO\IOInterface' ) -> getMock (), $this -> getConfigMock ());
2012-03-05 10:26:07 +00:00
2014-02-26 15:01:31 +00:00
$this -> assertNull ( $this -> callCallbackGet ( $fs , STREAM_NOTIFY_FAILURE , 0 , 'HTTP/1.1 404 Not Found' , 404 , 0 , 0 ));
2012-03-05 10:26:07 +00:00
}
2015-06-21 05:46:08 +00:00
/**
* @ group slow
*/
2013-06-17 13:41:48 +00:00
public function testCaptureAuthenticationParamsFromUrl ()
{
2018-04-12 08:24:56 +00:00
$io = $this -> getMockBuilder ( 'Composer\IO\IOInterface' ) -> getMock ();
2013-07-31 12:40:38 +00:00
$io -> expects ( $this -> once ())
-> method ( 'setAuthentication' )
2016-05-07 07:21:19 +00:00
-> with ( $this -> equalTo ( 'github.com' ), $this -> equalTo ( 'user' ), $this -> equalTo ( 'pass' ));
2013-06-17 13:41:48 +00:00
2018-11-14 16:54:19 +00:00
$fs = new RemoteFilesystem ( $io , $this -> getConfigMock ());
2013-07-31 12:40:38 +00:00
try {
2016-05-07 07:21:19 +00:00
$fs -> getContents ( 'github.com' , 'https://user:pass@github.com/composer/composer/404' );
2013-07-31 12:40:38 +00:00
} catch ( \Exception $e ) {
$this -> assertInstanceOf ( 'Composer\Downloader\TransportException' , $e );
2016-05-07 07:21:19 +00:00
$this -> assertNotEquals ( 200 , $e -> getCode ());
2013-07-31 12:40:38 +00:00
}
2013-06-17 13:41:48 +00:00
}
2012-03-05 10:26:07 +00:00
public function testGetContents ()
{
2018-11-14 16:54:19 +00:00
$fs = new RemoteFilesystem ( $this -> getMockBuilder ( 'Composer\IO\IOInterface' ) -> getMock (), $this -> getConfigMock ());
2012-03-05 10:26:07 +00:00
2012-03-29 13:09:01 +00:00
$this -> assertContains ( 'testGetContents' , $fs -> getContents ( 'http://example.org' , 'file://' . __FILE__ ));
2012-03-05 10:26:07 +00:00
}
public function testCopy ()
{
2018-11-14 16:54:19 +00:00
$fs = new RemoteFilesystem ( $this -> getMockBuilder ( 'Composer\IO\IOInterface' ) -> getMock (), $this -> getConfigMock ());
2012-03-05 10:26:07 +00:00
$file = tempnam ( sys_get_temp_dir (), 'c' );
2012-03-29 13:09:01 +00:00
$this -> assertTrue ( $fs -> copy ( 'http://example.org' , 'file://' . __FILE__ , $file ));
2012-03-05 10:26:07 +00:00
$this -> assertFileExists ( $file );
2012-03-29 13:09:01 +00:00
$this -> assertContains ( 'testCopy' , file_get_contents ( $file ));
2012-03-05 10:26:07 +00:00
unlink ( $file );
}
2014-02-23 13:33:29 +00:00
/**
* @ group TLS
*/
public function testGetOptionsForUrlCreatesSecureTlsDefaults ()
{
2018-04-12 08:24:56 +00:00
$io = $this -> getMockBuilder ( 'Composer\IO\IOInterface' ) -> getMock ();
2014-02-23 13:33:29 +00:00
2016-01-26 13:07:05 +00:00
$res = $this -> callGetOptionsForUrl ( $io , array ( 'example.org' , array ( 'ssl' => array ( 'cafile' => '/some/path/file.crt' ))), array (), 'http://www.example.org' );
2014-02-23 13:33:29 +00:00
$this -> assertTrue ( isset ( $res [ 'ssl' ][ 'ciphers' ]));
2016-06-11 10:19:58 +00:00
$this -> assertRegExp ( " |!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA| " , $res [ 'ssl' ][ 'ciphers' ]);
2014-02-23 13:33:29 +00:00
$this -> assertTrue ( $res [ 'ssl' ][ 'verify_peer' ]);
$this -> assertTrue ( $res [ 'ssl' ][ 'SNI_enabled' ]);
$this -> assertEquals ( 7 , $res [ 'ssl' ][ 'verify_depth' ]);
2016-01-16 16:43:33 +00:00
if ( PHP_VERSION_ID < 50600 ) {
$this -> assertEquals ( 'www.example.org' , $res [ 'ssl' ][ 'CN_match' ]);
$this -> assertEquals ( 'www.example.org' , $res [ 'ssl' ][ 'SNI_server_name' ]);
}
2014-02-23 13:33:29 +00:00
$this -> assertEquals ( '/some/path/file.crt' , $res [ 'ssl' ][ 'cafile' ]);
if ( version_compare ( PHP_VERSION , '5.4.13' ) >= 0 ) {
$this -> assertTrue ( $res [ 'ssl' ][ 'disable_compression' ]);
2014-02-23 14:15:24 +00:00
} else {
$this -> assertFalse ( isset ( $res [ 'ssl' ][ 'disable_compression' ]));
2014-02-23 13:33:29 +00:00
}
}
2016-09-28 17:08:24 +00:00
/**
* Provides URLs to public downloads at BitBucket .
*
* @ return string [][]
*/
public function provideBitbucketPublicDownloadUrls ()
{
return array (
2016-09-29 15:29:09 +00:00
array ( 'https://bitbucket.org/seldaek/composer-live-test-repo/downloads/composer-unit-test-download-me.txt' , '1234' ),
2016-09-28 17:08:24 +00:00
);
}
/**
* Tests that a BitBucket public download is correctly retrieved .
*
* @ param string $url
* @ param string $contents
* @ dataProvider provideBitbucketPublicDownloadUrls
*/
public function testBitBucketPublicDownload ( $url , $contents )
{
$io = $this
-> getMockBuilder ( 'Composer\IO\ConsoleIO' )
-> disableOriginalConstructor ()
-> getMock ();
2018-11-14 16:54:19 +00:00
$rfs = new RemoteFilesystem ( $io , $this -> getConfigMock ());
2016-09-28 17:08:24 +00:00
$hostname = parse_url ( $url , PHP_URL_HOST );
$result = $rfs -> getContents ( $hostname , $url , false );
$this -> assertEquals ( $contents , $result );
}
/**
* Tests that a BitBucket public download is correctly retrieved when `bitbucket-oauth` is configured .
*
* @ param string $url
* @ param string $contents
* @ dataProvider provideBitbucketPublicDownloadUrls
*/
public function testBitBucketPublicDownloadWithAuthConfigured ( $url , $contents )
{
$io = $this
-> getMockBuilder ( 'Composer\IO\ConsoleIO' )
-> disableOriginalConstructor ()
-> getMock ();
2017-11-29 15:37:00 +00:00
$domains = array ();
2016-09-28 17:08:24 +00:00
$io
2017-11-29 15:37:00 +00:00
-> expects ( $this -> any ())
2016-09-28 17:08:24 +00:00
-> method ( 'hasAuthentication' )
2017-12-18 15:02:48 +00:00
-> will ( $this -> returnCallback ( function ( $arg ) use ( & $domains ) {
2017-11-29 15:37:00 +00:00
$domains [] = $arg ;
// first time is called with bitbucket.org, then it redirects to bbuseruploads.s3.amazonaws.com so next time we have no auth configured
return $arg === 'bitbucket.org' ;
}));
2016-09-28 17:08:24 +00:00
$io
2017-11-29 15:37:00 +00:00
-> expects ( $this -> at ( 1 ))
2016-09-28 17:08:24 +00:00
-> method ( 'getAuthentication' )
-> with ( 'bitbucket.org' )
-> willReturn ( array (
'username' => 'x-token-auth' ,
// This token is fake, but it matches a valid token's pattern.
2017-03-08 14:07:29 +00:00
'password' => '1A0yeK5Po3ZEeiiRiMWLivS0jirLdoGuaSGq9NvESFx1Fsdn493wUDXC8rz_1iKVRTl1GINHEUCsDxGh5lZ=' ,
2016-09-28 17:08:24 +00:00
));
2018-11-14 16:54:19 +00:00
$rfs = new RemoteFilesystem ( $io , $this -> getConfigMock ());
2016-09-28 17:08:24 +00:00
$hostname = parse_url ( $url , PHP_URL_HOST );
$result = $rfs -> getContents ( $hostname , $url , false );
$this -> assertEquals ( $contents , $result );
2017-11-29 15:37:00 +00:00
$this -> assertEquals ( array ( 'bitbucket.org' , 'bbuseruploads.s3.amazonaws.com' ), $domains );
2016-09-28 17:08:24 +00:00
}
2014-02-28 18:46:49 +00:00
protected function callGetOptionsForUrl ( $io , array $args = array (), array $options = array (), $fileUrl = '' )
2012-03-05 10:26:07 +00:00
{
2018-11-14 16:54:19 +00:00
$fs = new RemoteFilesystem ( $io , $this -> getConfigMock (), $options );
2012-03-05 10:26:07 +00:00
$ref = new \ReflectionMethod ( $fs , 'getOptionsForUrl' );
2014-02-28 18:46:49 +00:00
$prop = new \ReflectionProperty ( $fs , 'fileUrl' );
2012-03-05 10:26:07 +00:00
$ref -> setAccessible ( true );
2014-02-28 18:46:49 +00:00
$prop -> setAccessible ( true );
$prop -> setValue ( $fs , $fileUrl );
2012-03-05 10:26:07 +00:00
return $ref -> invokeArgs ( $fs , $args );
}
protected function callCallbackGet ( RemoteFilesystem $fs , $notificationCode , $severity , $message , $messageCode , $bytesTransferred , $bytesMax )
{
$ref = new \ReflectionMethod ( $fs , 'callbackGet' );
$ref -> setAccessible ( true );
$ref -> invoke ( $fs , $notificationCode , $severity , $message , $messageCode , $bytesTransferred , $bytesMax );
}
protected function setAttribute ( $object , $attribute , $value )
{
$attr = new \ReflectionProperty ( $object , $attribute );
$attr -> setAccessible ( true );
$attr -> setValue ( $object , $value );
}
}