You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1062 lines
41KB

  1. <?php
  2. /*
  3. * This file is part of the Fxp Composer Asset Plugin package.
  4. *
  5. * (c) François Pluchino <francois.pluchino@gmail.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Fxp\Composer\AssetPlugin\Tests\Repository\Vcs;
  11. use Composer\Cache;
  12. use Composer\Downloader\TransportException;
  13. use Composer\IO\IOInterface;
  14. use Composer\Util\Filesystem;
  15. use Composer\Config;
  16. use Composer\Config\ConfigSourceInterface;
  17. use Composer\Util\ProcessExecutor;
  18. use Composer\Util\RemoteFilesystem;
  19. use Fxp\Composer\AssetPlugin\Repository\Vcs\GitHubDriver;
  20. /**
  21. * Tests of vcs github repository.
  22. *
  23. * @author François Pluchino <francois.pluchino@gmail.com>
  24. */
  25. class GitHubDriverTest extends \PHPUnit_Framework_TestCase
  26. {
  27. /**
  28. * @var Config
  29. */
  30. private $config;
  31. public function setUp()
  32. {
  33. $this->config = new Config();
  34. $this->config->merge(array(
  35. 'config' => array(
  36. 'home' => sys_get_temp_dir().'/composer-test',
  37. 'cache-repo-dir' => sys_get_temp_dir().'/composer-test-cache',
  38. ),
  39. ));
  40. }
  41. public function tearDown()
  42. {
  43. $fs = new Filesystem();
  44. $fs->removeDirectory(sys_get_temp_dir().'/composer-test');
  45. $fs->removeDirectory(sys_get_temp_dir().'/composer-test-cache');
  46. }
  47. public function getAssetTypes()
  48. {
  49. return array(
  50. array('npm', 'package.json'),
  51. array('bower', 'bower.json'),
  52. );
  53. }
  54. /**
  55. * @dataProvider getAssetTypes
  56. */
  57. public function testPrivateRepository($type, $filename)
  58. {
  59. $repoUrl = 'http://github.com/composer-test/repo-name';
  60. $repoApiUrl = 'https://api.github.com/repos/composer-test/repo-name';
  61. $repoSshUrl = 'git@github.com:composer-test/repo-name.git';
  62. $identifier = 'v0.0.0';
  63. $sha = 'SOMESHA';
  64. $io = $this->getMock('Composer\IO\IOInterface');
  65. $io->expects($this->any())
  66. ->method('isInteractive')
  67. ->will($this->returnValue(true));
  68. $remoteFilesystem = $this->getMockBuilder('Composer\Util\RemoteFilesystem')
  69. ->setConstructorArgs(array($io))
  70. ->getMock();
  71. $process = $this->getMock('Composer\Util\ProcessExecutor');
  72. $process->expects($this->any())
  73. ->method('execute')
  74. ->will($this->returnValue(1));
  75. $remoteFilesystem->expects($this->at(0))
  76. ->method('getContents')
  77. ->with($this->equalTo('github.com'), $this->equalTo($repoApiUrl), $this->equalTo(false))
  78. ->will($this->throwException(new TransportException('HTTP/1.1 404 Not Found', 404)));
  79. $io->expects($this->once())
  80. ->method('askAndHideAnswer')
  81. ->with($this->equalTo('Token (hidden): '))
  82. ->will($this->returnValue('sometoken'));
  83. $io->expects($this->any())
  84. ->method('setAuthentication')
  85. ->with($this->equalTo('github.com'), $this->matchesRegularExpression('{sometoken|abcdef}'), $this->matchesRegularExpression('{x-oauth-basic}'));
  86. $remoteFilesystem->expects($this->at(1))
  87. ->method('getContents')
  88. ->with($this->equalTo('github.com'), $this->equalTo('https://github.com/composer-test/repo-name'), $this->equalTo(false))
  89. ->will($this->returnValue(''));
  90. $remoteFilesystem->expects($this->at(2))
  91. ->method('getContents')
  92. ->will($this->returnValue(''));
  93. $remoteFilesystem->expects($this->at(3))
  94. ->method('getContents')
  95. ->with($this->equalTo('github.com'), $this->equalTo($repoApiUrl), $this->equalTo(false))
  96. ->will($this->throwException(new TransportException('HTTP/1.1 404 Not Found', 404)));
  97. $remoteFilesystem->expects($this->at(4))
  98. ->method('getContents')
  99. ->with($this->equalTo('github.com'), $this->equalTo('https://api.github.com/rate_limit'), $this->equalTo(false))
  100. ->will($this->returnValue('{}'));
  101. $remoteFilesystem->expects($this->at(5))
  102. ->method('getContents')
  103. ->with($this->equalTo('github.com'), $this->equalTo($repoApiUrl), $this->equalTo(false))
  104. ->will($this->returnValue($this->createJsonComposer(array('master_branch' => 'test_master', 'private' => true))));
  105. $configSource = $this->getMock('Composer\Config\ConfigSourceInterface');
  106. $authConfigSource = $this->getMock('Composer\Config\ConfigSourceInterface');
  107. /* @var ConfigSourceInterface $configSource */
  108. /* @var ConfigSourceInterface $authConfigSource */
  109. /* @var ProcessExecutor $process */
  110. /* @var RemoteFilesystem $remoteFilesystem */
  111. /* @var IOInterface $io */
  112. $this->config->setConfigSource($configSource);
  113. $this->config->setAuthConfigSource($authConfigSource);
  114. $repoConfig = array(
  115. 'url' => $repoUrl,
  116. 'asset-type' => $type,
  117. 'filename' => $filename,
  118. );
  119. $gitHubDriver = new GitHubDriver($repoConfig, $io, $this->config, $process, $remoteFilesystem);
  120. $gitHubDriver->initialize();
  121. $this->setAttribute($gitHubDriver, 'tags', array($identifier => $sha));
  122. $this->assertEquals('test_master', $gitHubDriver->getRootIdentifier());
  123. $dist = $gitHubDriver->getDist($sha);
  124. $this->assertEquals('zip', $dist['type']);
  125. $this->assertEquals('https://api.github.com/repos/composer-test/repo-name/zipball/SOMESHA', $dist['url']);
  126. $this->assertEquals('SOMESHA', $dist['reference']);
  127. $source = $gitHubDriver->getSource($sha);
  128. $this->assertEquals('git', $source['type']);
  129. $this->assertEquals($repoSshUrl, $source['url']);
  130. $this->assertEquals('SOMESHA', $source['reference']);
  131. }
  132. /**
  133. * @dataProvider getAssetTypes
  134. */
  135. public function testPublicRepository($type, $filename)
  136. {
  137. $repoUrl = 'http://github.com/composer-test/repo-name';
  138. $repoApiUrl = 'https://api.github.com/repos/composer-test/repo-name';
  139. $identifier = 'v0.0.0';
  140. $sha = 'SOMESHA';
  141. $io = $this->getMock('Composer\IO\IOInterface');
  142. $io->expects($this->any())
  143. ->method('isInteractive')
  144. ->will($this->returnValue(true));
  145. $remoteFilesystem = $this->getMockBuilder('Composer\Util\RemoteFilesystem')
  146. ->setConstructorArgs(array($io))
  147. ->getMock();
  148. $remoteFilesystem->expects($this->at(0))
  149. ->method('getContents')
  150. ->with($this->equalTo('github.com'), $this->equalTo($repoApiUrl), $this->equalTo(false))
  151. ->will($this->returnValue($this->createJsonComposer(array('master_branch' => 'test_master'))));
  152. $repoConfig = array(
  153. 'url' => $repoUrl,
  154. 'asset-type' => $type,
  155. 'filename' => $filename,
  156. );
  157. $repoUrl = 'https://github.com/composer-test/repo-name.git';
  158. /* @var IOInterface $io */
  159. /* @var RemoteFilesystem $remoteFilesystem */
  160. $gitHubDriver = new GitHubDriver($repoConfig, $io, $this->config, null, $remoteFilesystem);
  161. $gitHubDriver->initialize();
  162. $this->setAttribute($gitHubDriver, 'tags', array($identifier => $sha));
  163. $this->assertEquals('test_master', $gitHubDriver->getRootIdentifier());
  164. $dist = $gitHubDriver->getDist($sha);
  165. $this->assertEquals('zip', $dist['type']);
  166. $this->assertEquals('https://api.github.com/repos/composer-test/repo-name/zipball/SOMESHA', $dist['url']);
  167. $this->assertEquals($sha, $dist['reference']);
  168. $source = $gitHubDriver->getSource($sha);
  169. $this->assertEquals('git', $source['type']);
  170. $this->assertEquals($repoUrl, $source['url']);
  171. $this->assertEquals($sha, $source['reference']);
  172. }
  173. /**
  174. * @dataProvider getAssetTypes
  175. */
  176. public function testPublicRepository2($type, $filename)
  177. {
  178. $repoUrl = 'http://github.com/composer-test/repo-name';
  179. $repoApiUrl = 'https://api.github.com/repos/composer-test/repo-name';
  180. $identifier = 'feature/3.2-foo';
  181. $sha = 'SOMESHA';
  182. $io = $this->getMock('Composer\IO\IOInterface');
  183. $io->expects($this->any())
  184. ->method('isInteractive')
  185. ->will($this->returnValue(true));
  186. $remoteFilesystem = $this->getMockBuilder('Composer\Util\RemoteFilesystem')
  187. ->setConstructorArgs(array($io))
  188. ->getMock();
  189. $remoteFilesystem->expects($this->at(0))
  190. ->method('getContents')
  191. ->with($this->equalTo('github.com'), $this->equalTo($repoApiUrl), $this->equalTo(false))
  192. ->will($this->returnValue($this->createJsonComposer(array('master_branch' => 'test_master'))));
  193. $remoteFilesystem->expects($this->at(1))
  194. ->method('getContents')
  195. ->with($this->equalTo('github.com'), $this->equalTo('https://api.github.com/repos/composer-test/repo-name/contents/'.$filename.'?ref=feature%2F3.2-foo'), $this->equalTo(false))
  196. ->will($this->returnValue('{"encoding":"base64","content":"'.base64_encode('{"support": {"source": "'.$repoUrl.'" }}').'"}'));
  197. $remoteFilesystem->expects($this->at(2))
  198. ->method('getContents')
  199. ->with($this->equalTo('github.com'), $this->equalTo('https://api.github.com/repos/composer-test/repo-name/commits/feature%2F3.2-foo'), $this->equalTo(false))
  200. ->will($this->returnValue('{"commit": {"committer":{ "date": "2012-09-10"}}}'));
  201. $repoConfig = array(
  202. 'url' => $repoUrl,
  203. 'asset-type' => $type,
  204. 'filename' => $filename,
  205. );
  206. $repoUrl = 'https://github.com/composer-test/repo-name.git';
  207. /* @var IOInterface $io */
  208. /* @var RemoteFilesystem $remoteFilesystem */
  209. $gitHubDriver = new GitHubDriver($repoConfig, $io, $this->config, null, $remoteFilesystem);
  210. $gitHubDriver->initialize();
  211. $this->setAttribute($gitHubDriver, 'tags', array($identifier => $sha));
  212. $this->assertEquals('test_master', $gitHubDriver->getRootIdentifier());
  213. $dist = $gitHubDriver->getDist($sha);
  214. $this->assertEquals('zip', $dist['type']);
  215. $this->assertEquals('https://api.github.com/repos/composer-test/repo-name/zipball/SOMESHA', $dist['url']);
  216. $this->assertEquals($sha, $dist['reference']);
  217. $source = $gitHubDriver->getSource($sha);
  218. $this->assertEquals('git', $source['type']);
  219. $this->assertEquals($repoUrl, $source['url']);
  220. $this->assertEquals($sha, $source['reference']);
  221. $gitHubDriver->getComposerInformation($identifier);
  222. }
  223. /**
  224. * @dataProvider getAssetTypes
  225. */
  226. public function testPrivateRepositoryNoInteraction($type, $filename)
  227. {
  228. $repoUrl = 'http://github.com/composer-test/repo-name';
  229. $repoApiUrl = 'https://api.github.com/repos/composer-test/repo-name';
  230. $repoSshUrl = 'git@github.com:composer-test/repo-name.git';
  231. $identifier = 'v0.0.0';
  232. $sha = 'SOMESHA';
  233. $process = $this->getMockBuilder('Composer\Util\ProcessExecutor')
  234. ->disableOriginalConstructor()
  235. ->getMock();
  236. $io = $this->getMock('Composer\IO\IOInterface');
  237. $io->expects($this->any())
  238. ->method('isInteractive')
  239. ->will($this->returnValue(false));
  240. $remoteFilesystem = $this->getMockBuilder('Composer\Util\RemoteFilesystem')
  241. ->setConstructorArgs(array($io))
  242. ->getMock();
  243. $remoteFilesystem->expects($this->at(0))
  244. ->method('getContents')
  245. ->with($this->equalTo('github.com'), $this->equalTo($repoApiUrl), $this->equalTo(false))
  246. ->will($this->throwException(new TransportException('HTTP/1.1 404 Not Found', 404)));
  247. $remoteFilesystem->expects($this->at(1))
  248. ->method('getContents')
  249. ->with($this->equalTo('github.com'), $this->equalTo('https://github.com/composer-test/repo-name'), $this->equalTo(false))
  250. ->will($this->returnValue(''));
  251. $remoteFilesystem->expects($this->at(2))
  252. ->method('getContents')
  253. ->will($this->returnValue(''));
  254. $remoteFilesystem->expects($this->at(3))
  255. ->method('getContents')
  256. ->with($this->equalTo('github.com'), $this->equalTo($repoApiUrl), $this->equalTo(false))
  257. ->will($this->throwException(new TransportException('HTTP/1.1 404 Not Found', 404)));
  258. // clean local clone if present
  259. $fs = new Filesystem();
  260. $fs->removeDirectory(sys_get_temp_dir().'/composer-test');
  261. $process->expects($this->at(0))
  262. ->method('execute')
  263. ->with($this->equalTo('git config github.accesstoken'))
  264. ->will($this->returnValue(1));
  265. $process->expects($this->at(1))
  266. ->method('execute')
  267. ->with($this->stringContains($repoSshUrl))
  268. ->will($this->returnValue(0));
  269. $process->expects($this->at(2))
  270. ->method('execute')
  271. ->with($this->stringContains('git show-ref --tags'));
  272. $process->expects($this->at(3))
  273. ->method('splitLines')
  274. ->will($this->returnValue(array($sha.' refs/tags/'.$identifier)));
  275. $process->expects($this->at(4))
  276. ->method('execute')
  277. ->with($this->stringContains('git branch --no-color --no-abbrev -v'));
  278. $process->expects($this->at(5))
  279. ->method('splitLines')
  280. ->will($this->returnValue(array(' test_master edf93f1fccaebd8764383dc12016d0a1a9672d89 Fix test & behavior')));
  281. $process->expects($this->at(6))
  282. ->method('execute')
  283. ->with($this->stringContains('git branch --no-color'));
  284. $process->expects($this->at(7))
  285. ->method('splitLines')
  286. ->will($this->returnValue(array('* test_master')));
  287. $repoConfig = array(
  288. 'url' => $repoUrl,
  289. 'asset-type' => $type,
  290. 'filename' => $filename,
  291. );
  292. /* @var IOInterface $io */
  293. /* @var RemoteFilesystem $remoteFilesystem */
  294. /* @var ProcessExecutor $process */
  295. $gitHubDriver = new GitHubDriver($repoConfig, $io, $this->config, $process, $remoteFilesystem);
  296. $gitHubDriver->initialize();
  297. $this->assertEquals('test_master', $gitHubDriver->getRootIdentifier());
  298. $dist = $gitHubDriver->getDist($sha);
  299. $this->assertEquals('zip', $dist['type']);
  300. $this->assertEquals('https://api.github.com/repos/composer-test/repo-name/zipball/SOMESHA', $dist['url']);
  301. $this->assertEquals($sha, $dist['reference']);
  302. $source = $gitHubDriver->getSource($identifier);
  303. $this->assertEquals('git', $source['type']);
  304. $this->assertEquals($repoSshUrl, $source['url']);
  305. $this->assertEquals($identifier, $source['reference']);
  306. $source = $gitHubDriver->getSource($sha);
  307. $this->assertEquals('git', $source['type']);
  308. $this->assertEquals($repoSshUrl, $source['url']);
  309. $this->assertEquals($sha, $source['reference']);
  310. }
  311. /**
  312. * @dataProvider getAssetTypes
  313. */
  314. public function testGetComposerInformationWithGitDriver($type, $filename)
  315. {
  316. $repoUrl = 'https://github.com/composer-test/repo-name';
  317. $identifier = 'v0.0.0';
  318. $io = $this->getMock('Composer\IO\IOInterface');
  319. $io->expects($this->any())
  320. ->method('isInteractive')
  321. ->will($this->returnValue(true));
  322. $repoConfig = array(
  323. 'url' => $repoUrl,
  324. 'asset-type' => $type,
  325. 'filename' => $filename,
  326. 'no-api' => true,
  327. );
  328. $process = $this->getMock('Composer\Util\ProcessExecutor');
  329. $process->expects($this->any())
  330. ->method('splitLines')
  331. ->will($this->returnValue(array()));
  332. $process->expects($this->any())
  333. ->method('execute')
  334. ->will($this->returnCallback(function () {
  335. return 0;
  336. }));
  337. /* @var IOInterface $io */
  338. /* @var ProcessExecutor $process */
  339. $gitHubDriver = new GitHubDriver($repoConfig, $io, $this->config, $process, null);
  340. $gitHubDriver->initialize();
  341. $validEmpty = array(
  342. '_nonexistent_package' => true,
  343. );
  344. $this->assertSame($validEmpty, $gitHubDriver->getComposerInformation($identifier));
  345. }
  346. /**
  347. * @dataProvider getAssetTypes
  348. */
  349. public function testGetComposerInformationWithCodeCache($type, $filename)
  350. {
  351. $repoUrl = 'http://github.com/composer-test/repo-name';
  352. $repoApiUrl = 'https://api.github.com/repos/composer-test/repo-name';
  353. $identifier = 'dev-master';
  354. $sha = '92bebbfdcde75ef2368317830e54b605bc938123';
  355. $io = $this->getMock('Composer\IO\IOInterface');
  356. $io->expects($this->any())
  357. ->method('isInteractive')
  358. ->will($this->returnValue(true));
  359. /* @var IOInterface $io */
  360. /* @var RemoteFilesystem $remoteFilesystem */
  361. $remoteFilesystem = $this->createMockRremoteFilesystem($io, $repoApiUrl, $filename, $sha, false);
  362. $repoConfig = array(
  363. 'url' => $repoUrl,
  364. 'asset-type' => $type,
  365. 'filename' => $filename,
  366. );
  367. $gitHubDriver = new GitHubDriver($repoConfig, $io, $this->config, null, $remoteFilesystem);
  368. $gitHubDriver->initialize();
  369. $this->setAttribute($gitHubDriver, 'tags', array($identifier => $sha));
  370. $this->setAttribute($gitHubDriver, 'hasIssues', true);
  371. $composer1 = $gitHubDriver->getComposerInformation($sha);
  372. $composer2 = $gitHubDriver->getComposerInformation($sha);
  373. $this->assertSame($composer1, $composer2);
  374. }
  375. /**
  376. * @dataProvider getAssetTypes
  377. */
  378. public function testGetComposerInformationWithFilesystemCache($type, $filename)
  379. {
  380. $repoUrl = 'http://github.com/composer-test/repo-name';
  381. $repoApiUrl = 'https://api.github.com/repos/composer-test/repo-name';
  382. $identifier = 'dev-master';
  383. $sha = '92bebbfdcde75ef2368317830e54b605bc938123';
  384. $io = $this->getMock('Composer\IO\IOInterface');
  385. $io->expects($this->any())
  386. ->method('isInteractive')
  387. ->will($this->returnValue(true));
  388. /* @var IOInterface $io */
  389. /* @var RemoteFilesystem $remoteFilesystem1 */
  390. $remoteFilesystem1 = $this->createMockRremoteFilesystem($io, $repoApiUrl, $filename, $sha, false);
  391. /* @var RemoteFilesystem $remoteFilesystem2 */
  392. $remoteFilesystem2 = $this->createMockRremoteFilesystem($io, $repoApiUrl, $filename, $sha, true);
  393. $repoConfig = array(
  394. 'url' => $repoUrl,
  395. 'asset-type' => $type,
  396. 'filename' => $filename,
  397. );
  398. $gitHubDriver1 = new GitHubDriver($repoConfig, $io, $this->config, null, $remoteFilesystem1);
  399. $gitHubDriver2 = new GitHubDriver($repoConfig, $io, $this->config, null, $remoteFilesystem2);
  400. $gitHubDriver1->initialize();
  401. $gitHubDriver2->initialize();
  402. $this->setAttribute($gitHubDriver1, 'tags', array($identifier => $sha));
  403. $this->setAttribute($gitHubDriver1, 'hasIssues', true);
  404. $this->setAttribute($gitHubDriver2, 'tags', array($identifier => $sha));
  405. $this->setAttribute($gitHubDriver2, 'hasIssues', true);
  406. $composer1 = $gitHubDriver1->getComposerInformation($sha);
  407. $composer2 = $gitHubDriver2->getComposerInformation($sha);
  408. $this->assertSame($composer1, $composer2);
  409. }
  410. /**
  411. * @dataProvider getAssetTypes
  412. */
  413. public function testGetComposerInformationWithEmptyContent($type, $filename)
  414. {
  415. $repoUrl = 'http://github.com/composer-test/repo-name';
  416. $repoApiUrl = 'https://api.github.com/repos/composer-test/repo-name';
  417. $identifier = 'v0.0.0';
  418. $io = $this->getMock('Composer\IO\IOInterface');
  419. $remoteFilesystem = $this->getMockBuilder('Composer\Util\RemoteFilesystem')
  420. ->setConstructorArgs(array($io))
  421. ->getMock();
  422. $remoteFilesystem->expects($this->at(0))
  423. ->method('getContents')
  424. ->with($this->equalTo('github.com'), $this->equalTo($repoApiUrl), $this->equalTo(false))
  425. ->will($this->returnValue($this->createJsonComposer(array('master_branch' => 'test_master'))));
  426. $remoteFilesystem->expects($this->at(1))
  427. ->method('getContents')
  428. ->with($this->equalTo('github.com'), $this->equalTo('https://api.github.com/repos/composer-test/repo-name/contents/'.$filename.'?ref='.$identifier), $this->equalTo(false))
  429. ->will($this->throwException(new TransportException('Not Found', 404)));
  430. $remoteFilesystem->expects($this->at(2))
  431. ->method('getContents')
  432. ->with($this->equalTo('github.com'), $this->equalTo('https://api.github.com/repos/composer-test/repo-name/contents/'.$filename.'?ref='.$identifier), $this->equalTo(false))
  433. ->will($this->throwException(new TransportException('Not Found', 404)));
  434. $repoConfig = array(
  435. 'url' => $repoUrl,
  436. 'asset-type' => $type,
  437. 'filename' => $filename,
  438. );
  439. /* @var IOInterface $io */
  440. /* @var RemoteFilesystem $remoteFilesystem */
  441. $gitHubDriver = new GitHubDriver($repoConfig, $io, $this->config, null, $remoteFilesystem);
  442. $gitHubDriver->initialize();
  443. $validEmpty = array(
  444. '_nonexistent_package' => true,
  445. );
  446. $this->assertSame($validEmpty, $gitHubDriver->getComposerInformation($identifier));
  447. }
  448. /**
  449. * @dataProvider getAssetTypes
  450. */
  451. public function testGetComposerInformationWithRuntimeException($type, $filename)
  452. {
  453. $this->setExpectedException('RuntimeException');
  454. $repoUrl = 'http://github.com/composer-test/repo-name';
  455. $repoApiUrl = 'https://api.github.com/repos/composer-test/repo-name';
  456. $identifier = 'v0.0.0';
  457. $io = $this->getMock('Composer\IO\IOInterface');
  458. $remoteFilesystem = $this->getMockBuilder('Composer\Util\RemoteFilesystem')
  459. ->setConstructorArgs(array($io))
  460. ->getMock();
  461. $remoteFilesystem->expects($this->at(0))
  462. ->method('getContents')
  463. ->with($this->equalTo('github.com'), $this->equalTo($repoApiUrl), $this->equalTo(false))
  464. ->will($this->returnValue($this->createJsonComposer(array('master_branch' => 'test_master'))));
  465. $remoteFilesystem->expects($this->at(1))
  466. ->method('getContents')
  467. ->with($this->equalTo('github.com'), $this->equalTo('https://api.github.com/repos/composer-test/repo-name/contents/'.$filename.'?ref='.$identifier), $this->equalTo(false))
  468. ->will($this->returnValue('{"encoding":"base64","content":""}'));
  469. $repoConfig = array(
  470. 'url' => $repoUrl,
  471. 'asset-type' => $type,
  472. 'filename' => $filename,
  473. );
  474. /* @var IOInterface $io */
  475. /* @var RemoteFilesystem $remoteFilesystem */
  476. $gitHubDriver = new GitHubDriver($repoConfig, $io, $this->config, null, $remoteFilesystem);
  477. $gitHubDriver->initialize();
  478. $gitHubDriver->getComposerInformation($identifier);
  479. }
  480. /**
  481. * @dataProvider getAssetTypes
  482. */
  483. public function testGetComposerInformationWithTransportException($type, $filename)
  484. {
  485. $this->setExpectedException('RuntimeException');
  486. $repoUrl = 'http://github.com/composer-test/repo-name';
  487. $repoApiUrl = 'https://api.github.com/repos/composer-test/repo-name';
  488. $identifier = 'v0.0.0';
  489. $io = $this->getMock('Composer\IO\IOInterface');
  490. $remoteFilesystem = $this->getMockBuilder('Composer\Util\RemoteFilesystem')
  491. ->setConstructorArgs(array($io))
  492. ->getMock();
  493. $remoteFilesystem->expects($this->at(0))
  494. ->method('getContents')
  495. ->with($this->equalTo('github.com'), $this->equalTo($repoApiUrl), $this->equalTo(false))
  496. ->will($this->returnValue($this->createJsonComposer(array('master_branch' => 'test_master'))));
  497. $remoteFilesystem->expects($this->at(1))
  498. ->method('getContents')
  499. ->with($this->equalTo('github.com'), $this->equalTo('https://api.github.com/repos/composer-test/repo-name/contents/'.$filename.'?ref='.$identifier), $this->equalTo(false))
  500. ->will($this->throwException(new TransportException('Mock exception code 404', 404)));
  501. $remoteFilesystem->expects($this->at(2))
  502. ->method('getContents')
  503. ->with($this->equalTo('github.com'), $this->equalTo('https://api.github.com/repos/composer-test/repo-name/contents/'.$filename.'?ref='.$identifier), $this->equalTo(false))
  504. ->will($this->throwException(new TransportException('Mock exception code 400', 400)));
  505. $repoConfig = array(
  506. 'url' => $repoUrl,
  507. 'asset-type' => $type,
  508. 'filename' => $filename,
  509. );
  510. /* @var IOInterface $io */
  511. /* @var RemoteFilesystem $remoteFilesystem */
  512. $gitHubDriver = new GitHubDriver($repoConfig, $io, $this->config, null, $remoteFilesystem);
  513. $gitHubDriver->initialize();
  514. $gitHubDriver->getComposerInformation($identifier);
  515. }
  516. /**
  517. * @dataProvider getAssetTypes
  518. */
  519. public function testRedirectUrlRepository($type, $filename)
  520. {
  521. $repoUrl = 'http://github.com/composer-test/repo-name';
  522. $repoApiUrl = 'https://api.github.com/repos/composer-test/repo-name';
  523. $identifier = 'v0.0.0';
  524. $sha = 'SOMESHA';
  525. $io = $this->getMock('Composer\IO\IOInterface');
  526. $io->expects($this->any())
  527. ->method('isInteractive')
  528. ->will($this->returnValue(true));
  529. $remoteFilesystem = $this->getMockBuilder('Composer\Util\RemoteFilesystem')
  530. ->setConstructorArgs(array($io))
  531. ->getMock();
  532. $remoteFilesystem->expects($this->at(0))
  533. ->method('getContents')
  534. ->with($this->equalTo('github.com'), $this->equalTo($repoApiUrl), $this->equalTo(false))
  535. ->will($this->throwException(new TransportException('HTTP/1.1 404 Not Found', 404)));
  536. $remoteFilesystem->expects($this->at(1))
  537. ->method('getContents')
  538. ->with($this->equalTo('github.com'), $this->equalTo('https://github.com/composer-test/repo-name'), $this->equalTo(false))
  539. ->will($this->returnValue(''));
  540. $remoteFilesystem->expects($this->at(2))
  541. ->method('getLastHeaders')
  542. ->will($this->returnValue(array(
  543. 'HTTP/1.1 301 Moved Permanently',
  544. 'Header-parameter: test',
  545. 'Location: '.$repoUrl.'-new',
  546. )));
  547. $remoteFilesystem->expects($this->at(3))
  548. ->method('getContents')
  549. ->with($this->equalTo('github.com'), $this->equalTo($repoApiUrl.'-new'), $this->equalTo(false))
  550. ->will($this->returnValue($this->createJsonComposer(array('master_branch' => 'test_master'))));
  551. $repoConfig = array(
  552. 'url' => $repoUrl,
  553. 'asset-type' => $type,
  554. 'filename' => $filename,
  555. );
  556. $repoUrl = 'https://github.com/composer-test/repo-name.git';
  557. /* @var IOInterface $io */
  558. /* @var RemoteFilesystem $remoteFilesystem */
  559. $gitHubDriver = new GitHubDriver($repoConfig, $io, $this->config, null, $remoteFilesystem);
  560. $gitHubDriver->initialize();
  561. $this->setAttribute($gitHubDriver, 'tags', array($identifier => $sha));
  562. $this->assertEquals('test_master', $gitHubDriver->getRootIdentifier());
  563. $dist = $gitHubDriver->getDist($sha);
  564. $this->assertEquals('zip', $dist['type']);
  565. $this->assertEquals('https://api.github.com/repos/composer-test/repo-name/zipball/SOMESHA', $dist['url']);
  566. $this->assertEquals($sha, $dist['reference']);
  567. $source = $gitHubDriver->getSource($sha);
  568. $this->assertEquals('git', $source['type']);
  569. $this->assertEquals($repoUrl, $source['url']);
  570. $this->assertEquals($sha, $source['reference']);
  571. }
  572. /**
  573. * @dataProvider getAssetTypes
  574. */
  575. public function testRedirectUrlWithNonexistentRepository($type, $filename)
  576. {
  577. $this->setExpectedException('RuntimeException');
  578. $repoUrl = 'http://github.com/composer-test/repo-name';
  579. $repoApiUrl = 'https://api.github.com/repos/composer-test/repo-name';
  580. $identifier = 'v0.0.0';
  581. $io = $this->getMock('Composer\IO\IOInterface');
  582. $io->expects($this->any())
  583. ->method('isInteractive')
  584. ->will($this->returnValue(true));
  585. $remoteFilesystem = $this->getMockBuilder('Composer\Util\RemoteFilesystem')
  586. ->setConstructorArgs(array($io))
  587. ->getMock();
  588. $remoteFilesystem->expects($this->at(0))
  589. ->method('getContents')
  590. ->with($this->equalTo('github.com'), $this->equalTo($repoApiUrl), $this->equalTo(false))
  591. ->will($this->throwException(new TransportException('HTTP/1.1 404 Not Found', 404)));
  592. $io->expects($this->once())
  593. ->method('askAndHideAnswer')
  594. ->with($this->equalTo('Token (hidden): '))
  595. ->will($this->returnValue('sometoken'));
  596. $io->expects($this->any())
  597. ->method('setAuthentication')
  598. ->with($this->equalTo('github.com'), $this->matchesRegularExpression('{sometoken|abcdef}'), $this->matchesRegularExpression('{x-oauth-basic}'));
  599. $remoteFilesystem->expects($this->at(1))
  600. ->method('getContents')
  601. ->with($this->equalTo('github.com'), $this->equalTo('https://github.com/composer-test/repo-name'), $this->equalTo(false))
  602. ->will($this->throwException(new TransportException('HTTP/1.1 404 Not Found', 404)));
  603. $remoteFilesystem->expects($this->at(2))
  604. ->method('getContents')
  605. ->with($this->equalTo('github.com'), $this->equalTo($repoApiUrl), $this->equalTo(false))
  606. ->will($this->throwException(new TransportException('HTTP/1.1 404 Not Found', 404)));
  607. $remoteFilesystem->expects($this->at(3))
  608. ->method('getContents')
  609. ->with($this->equalTo('github.com'), $this->equalTo('https://api.github.com/rate_limit'), $this->equalTo(false))
  610. ->will($this->returnValue('{}'));
  611. $remoteFilesystem->expects($this->at(4))
  612. ->method('getContents')
  613. ->with($this->equalTo('github.com'), $this->equalTo($repoApiUrl), $this->equalTo(false))
  614. ->will($this->throwException(new TransportException('HTTP/1.1 404 Not Found', 404)));
  615. $remoteFilesystem->expects($this->at(5))
  616. ->method('getContents')
  617. ->with($this->equalTo('github.com'), $this->equalTo($repoApiUrl.'/contents/'.$filename.'?ref='.$identifier), $this->equalTo(false))
  618. ->will($this->throwException(new TransportException('HTTP/1.1 404 Not Found', 404)));
  619. $configSource = $this->getMock('Composer\Config\ConfigSourceInterface');
  620. $authConfigSource = $this->getMock('Composer\Config\ConfigSourceInterface');
  621. /* @var ConfigSourceInterface $configSource */
  622. /* @var ConfigSourceInterface $authConfigSource */
  623. $this->config->setConfigSource($configSource);
  624. $this->config->setAuthConfigSource($authConfigSource);
  625. $repoConfig = array(
  626. 'url' => $repoUrl,
  627. 'asset-type' => $type,
  628. 'filename' => $filename,
  629. );
  630. /* @var IOInterface $io */
  631. /* @var RemoteFilesystem $remoteFilesystem */
  632. $gitHubDriver = new GitHubDriver($repoConfig, $io, $this->config, null, $remoteFilesystem);
  633. $firstNonexistent = false;
  634. try {
  635. $gitHubDriver->initialize();
  636. } catch (TransportException $e) {
  637. $firstNonexistent = true;
  638. }
  639. $this->assertTrue($firstNonexistent);
  640. $gitHubDriver->getComposerInformation($identifier);
  641. }
  642. /**
  643. * @dataProvider getAssetTypes
  644. */
  645. public function testRedirectUrlRepositoryWithCache($type, $filename)
  646. {
  647. $originUrl = 'github.com';
  648. $owner = 'composer-test';
  649. $repository = 'repo-name';
  650. $repoUrl = 'http://'.$originUrl.'/'.$owner.'/'.$repository;
  651. $repoApiUrl = 'https://api.github.com/repos/composer-test/repo-name';
  652. $repoApiUrlNew = $repoApiUrl.'-new';
  653. $identifier = 'v0.0.0';
  654. $sha = 'SOMESHA';
  655. $io = $this->getMock('Composer\IO\IOInterface');
  656. $io->expects($this->any())
  657. ->method('isInteractive')
  658. ->will($this->returnValue(true));
  659. $remoteFilesystem = $this->getMockBuilder('Composer\Util\RemoteFilesystem')
  660. ->setConstructorArgs(array($io))
  661. ->getMock();
  662. $remoteFilesystem->expects($this->at(0))
  663. ->method('getContents')
  664. ->with($this->equalTo('github.com'), $this->equalTo($repoApiUrlNew), $this->equalTo(false))
  665. ->will($this->returnValue($this->createJsonComposer(array('master_branch' => 'test_master'))));
  666. $repoConfig = array(
  667. 'url' => $repoUrl,
  668. 'asset-type' => $type,
  669. 'filename' => $filename,
  670. );
  671. $repoUrl = 'https://github.com/composer-test/repo-name.git';
  672. /* @var IOInterface $io */
  673. /* @var RemoteFilesystem $remoteFilesystem */
  674. $cache = new Cache($io, $this->config->get('cache-repo-dir').'/'.$originUrl.'/'.$owner.'/'.$repository);
  675. $cache->write('redirect-api', $repoApiUrlNew);
  676. $gitHubDriver = new GitHubDriver($repoConfig, $io, $this->config, null, $remoteFilesystem);
  677. $gitHubDriver->initialize();
  678. $this->setAttribute($gitHubDriver, 'tags', array($identifier => $sha));
  679. $this->assertEquals('test_master', $gitHubDriver->getRootIdentifier());
  680. $dist = $gitHubDriver->getDist($sha);
  681. $this->assertEquals('zip', $dist['type']);
  682. $this->assertEquals('https://api.github.com/repos/composer-test/repo-name/zipball/SOMESHA', $dist['url']);
  683. $this->assertEquals($sha, $dist['reference']);
  684. $source = $gitHubDriver->getSource($sha);
  685. $this->assertEquals('git', $source['type']);
  686. $this->assertEquals($repoUrl, $source['url']);
  687. $this->assertEquals($sha, $source['reference']);
  688. }
  689. public function getDataBranches()
  690. {
  691. $valid1 = array();
  692. $git1 = array();
  693. $valid2 = array(
  694. 'master' => '0123456789abcdef0123456789abcdef01234567',
  695. );
  696. $git2 = array(
  697. 'master 0123456789abcdef0123456789abcdef01234567 Comment',
  698. );
  699. $valid3 = array(
  700. 'gh-pages' => '0123456789abcdef0123456789abcdef01234567',
  701. );
  702. $git3 = array(
  703. 'gh-pages 0123456789abcdef0123456789abcdef01234567 Comment',
  704. );
  705. $valid4 = array(
  706. 'master' => '0123456789abcdef0123456789abcdef01234567',
  707. 'gh-pages' => '0123456789abcdef0123456789abcdef01234567',
  708. );
  709. $git4 = array(
  710. 'master 0123456789abcdef0123456789abcdef01234567 Comment',
  711. 'gh-pages 0123456789abcdef0123456789abcdef01234567 Comment',
  712. );
  713. return array(
  714. array('npm', 'package.json', $valid1, $git1),
  715. array('npm', 'package.json', $valid2, $git2),
  716. array('npm', 'package.json', $valid3, $git3),
  717. array('npm', 'package.json', $valid4, $git4),
  718. array('bower', 'bower.json', $valid1, $git1),
  719. array('bower', 'bower.json', $valid2, $git2),
  720. array('bower', 'bower.json', $valid3, $git3),
  721. array('bower', 'bower.json', $valid4, $git4),
  722. );
  723. }
  724. /**
  725. * @dataProvider getDataBranches
  726. */
  727. public function testGetBranchesWithGitDriver($type, $filename, array $branches, array $gitBranches)
  728. {
  729. $repoUrl = 'https://github.com/composer-test/repo-name';
  730. $io = $this->getMock('Composer\IO\IOInterface');
  731. $io->expects($this->any())
  732. ->method('isInteractive')
  733. ->will($this->returnValue(true));
  734. $repoConfig = array(
  735. 'url' => $repoUrl,
  736. 'asset-type' => $type,
  737. 'filename' => $filename,
  738. 'no-api' => true,
  739. );
  740. $process = $this->getMock('Composer\Util\ProcessExecutor');
  741. $process->expects($this->any())
  742. ->method('splitLines')
  743. ->will($this->returnValue($gitBranches));
  744. $process->expects($this->any())
  745. ->method('execute')
  746. ->will($this->returnCallback(function () {
  747. return 0;
  748. }));
  749. /* @var IOInterface $io */
  750. /* @var ProcessExecutor $process */
  751. $gitHubDriver = new GitHubDriver($repoConfig, $io, $this->config, $process, null);
  752. $gitHubDriver->initialize();
  753. $this->assertSame($branches, $gitHubDriver->getBranches());
  754. }
  755. /**
  756. * @dataProvider getDataBranches
  757. */
  758. public function testGetBranches($type, $filename, array $branches)
  759. {
  760. $repoUrl = 'http://github.com/composer-test/repo-name';
  761. $repoApiUrl = 'https://api.github.com/repos/composer-test/repo-name';
  762. $identifier = 'v0.0.0';
  763. $sha = 'SOMESHA';
  764. $io = $this->getMock('Composer\IO\IOInterface');
  765. $io->expects($this->any())
  766. ->method('isInteractive')
  767. ->will($this->returnValue(true));
  768. $remoteFilesystem = $this->getMockBuilder('Composer\Util\RemoteFilesystem')
  769. ->setConstructorArgs(array($io))
  770. ->getMock();
  771. $remoteFilesystem->expects($this->at(0))
  772. ->method('getContents')
  773. ->with($this->equalTo('github.com'), $this->equalTo($repoApiUrl), $this->equalTo(false))
  774. ->will($this->returnValue($this->createJsonComposer(array('master_branch' => 'gh-pages'))));
  775. $remoteFilesystem->expects($this->any())
  776. ->method('getLastHeaders')
  777. ->will($this->returnValue(array()));
  778. $githubBranches = array();
  779. foreach ($branches as $branch => $sha) {
  780. $githubBranches[] = array(
  781. 'ref' => 'refs/heads/'.$branch,
  782. 'object' => array(
  783. 'sha' => $sha,
  784. ),
  785. );
  786. }
  787. $remoteFilesystem->expects($this->at(1))
  788. ->method('getContents')
  789. ->will($this->returnValue(json_encode($githubBranches)));
  790. $repoConfig = array(
  791. 'url' => $repoUrl,
  792. 'asset-type' => $type,
  793. 'filename' => $filename,
  794. );
  795. /* @var IOInterface $io */
  796. /* @var RemoteFilesystem $remoteFilesystem */
  797. $gitHubDriver = new GitHubDriver($repoConfig, $io, $this->config, null, $remoteFilesystem);
  798. $gitHubDriver->initialize();
  799. $this->setAttribute($gitHubDriver, 'tags', array($identifier => $sha));
  800. $this->assertEquals('gh-pages', $gitHubDriver->getRootIdentifier());
  801. $this->assertSame($branches, $gitHubDriver->getBranches());
  802. }
  803. /**
  804. * @param object $object
  805. * @param string $attribute
  806. * @param mixed $value
  807. */
  808. protected function setAttribute($object, $attribute, $value)
  809. {
  810. $attr = new \ReflectionProperty($object, $attribute);
  811. $attr->setAccessible(true);
  812. $attr->setValue($object, $value);
  813. }
  814. /**
  815. * Creates the json composer content.
  816. *
  817. * @param array $content The composer content
  818. * @param string $name The name of repository
  819. * @param string $login The username /organization of repository
  820. *
  821. * @return string The json content
  822. */
  823. protected function createJsonComposer(array $content, $name = 'repo-name', $login = 'composer-test')
  824. {
  825. return json_encode(array_merge_recursive($content, array(
  826. 'name' => $name,
  827. 'owner' => array(
  828. 'login' => $login,
  829. ),
  830. )));
  831. }
  832. /**
  833. * @param IOInterface $io
  834. * @param string $repoApiUrl
  835. * @param string $filename
  836. * @param string $sha
  837. * @param bool $forCache
  838. *
  839. * @return \PHPUnit_Framework_MockObject_MockObject
  840. */
  841. protected function createMockRremoteFilesystem($io, $repoApiUrl, $filename, $sha, $forCache)
  842. {
  843. $remoteFilesystem = $this->getMockBuilder('Composer\Util\RemoteFilesystem')
  844. ->setConstructorArgs(array($io))
  845. ->getMock();
  846. $remoteFilesystem->expects($this->at(0))
  847. ->method('getContents')
  848. ->with($this->equalTo('github.com'), $this->equalTo($repoApiUrl), $this->equalTo(false))
  849. ->will($this->returnValue($this->createJsonComposer(array('master_branch' => 'test_master'))));
  850. if ($forCache) {
  851. return $remoteFilesystem;
  852. }
  853. $remoteFilesystem->expects($this->at(1))
  854. ->method('getContents')
  855. ->with($this->equalTo('github.com'), $this->equalTo('https://api.github.com/repos/composer-test/repo-name/contents/'.$filename.'?ref='.$sha), $this->equalTo(false))
  856. ->will($this->returnValue('{"encoding":"base64","content":"'.base64_encode('{"support": {}}').'"}'));
  857. $remoteFilesystem->expects($this->at(2))
  858. ->method('getContents')
  859. ->with($this->equalTo('github.com'), $this->equalTo('https://api.github.com/repos/composer-test/repo-name/commits/'.$sha), $this->equalTo(false))
  860. ->will($this->returnValue('{"commit": {"committer":{ "date": "2012-09-10"}}}'));
  861. return $remoteFilesystem;
  862. }
  863. }