UpdaterTest.php 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. <?php
  2. /**
  3. * Humbug
  4. *
  5. * @category Humbug
  6. * @package Humbug
  7. * @subpackage UnitTests
  8. * @copyright Copyright (c) 2015 Pádraic Brady (http://blog.astrumfutura.com)
  9. * @license https://github.com/padraic/pharupdater/blob/master/LICENSE New BSD License
  10. */
  11. namespace Humbug\Test\SelfUpdate;
  12. use Humbug\SelfUpdate\Updater;
  13. use Humbug\SelfUpdate\Strategy\StrategyInterface;
  14. class UpdaterTest extends \PHPUnit_Framework_TestCase
  15. {
  16. private $files;
  17. /** @var Updater */
  18. private $updater;
  19. private $tmp;
  20. public function setup()
  21. {
  22. $this->tmp = sys_get_temp_dir();
  23. $this->files = __DIR__ . '/_files';
  24. $this->updater = new Updater($this->files . '/test.phar');
  25. }
  26. public function teardown()
  27. {
  28. $this->deleteTempPhars();
  29. }
  30. public function testConstruction()
  31. {
  32. // with key
  33. $updater = new Updater($this->files . '/test.phar');
  34. $this->assertEquals($updater->getLocalPharFile(), $this->files . '/test.phar');
  35. $this->assertEquals($updater->getLocalPubKeyFile(), $this->files . '/test.phar.pubkey');
  36. // without key
  37. $updater = new Updater($this->files . '/test.phar', false);
  38. $this->assertEquals($updater->getLocalPharFile(), $this->files . '/test.phar');
  39. $this->assertNull($updater->getLocalPubKeyFile());
  40. // no name - detect running console app
  41. $updater = new Updater(null, false);
  42. $this->assertStringEndsWith(
  43. 'phpunit.phar',
  44. basename($updater->getLocalPharFile(), '.phar') . '.phar'
  45. );
  46. }
  47. public function testConstructorThrowsExceptionIfPubKeyNotExistsButFlagTrue()
  48. {
  49. $this->setExpectedException('Humbug\\SelfUpdate\\Exception\\RuntimeException');
  50. $updater = new Updater($this->files . '/test-nopubkey.phar');
  51. }
  52. public function testConstructorAncilliaryValues()
  53. {
  54. $this->assertEquals($this->updater->getLocalPharFileBasename(), 'test');
  55. $this->assertEquals($this->updater->getTempDirectory(), $this->files);
  56. }
  57. public function testSetPharUrlWithUrl()
  58. {
  59. $this->updater->getStrategy()->setPharUrl('http://www.example.com');
  60. $this->assertEquals($this->updater->getStrategy()->getPharUrl(), 'http://www.example.com');
  61. $this->updater->getStrategy()->setPharUrl('https://www.example.com');
  62. $this->assertEquals($this->updater->getStrategy()->getPharUrl(), 'https://www.example.com');
  63. }
  64. public function testSetPharUrlThrowsExceptionOnInvalidUrl()
  65. {
  66. $this->setExpectedException('Humbug\\SelfUpdate\\Exception\\InvalidArgumentException');
  67. $this->updater->getStrategy()->setPharUrl('silly:///home/padraic');
  68. }
  69. public function testSetVersionUrlWithUrl()
  70. {
  71. $this->updater->getStrategy()->setVersionUrl('http://www.example.com');
  72. $this->assertEquals($this->updater->getStrategy()->getVersionUrl(), 'http://www.example.com');
  73. $this->updater->getStrategy()->setVersionUrl('https://www.example.com');
  74. $this->assertEquals($this->updater->getStrategy()->getVersionUrl(), 'https://www.example.com');
  75. }
  76. public function testSetVersionUrlThrowsExceptionOnInvalidUrl()
  77. {
  78. $this->setExpectedException('Humbug\\SelfUpdate\\Exception\\InvalidArgumentException');
  79. $this->updater->getStrategy()->setVersionUrl('silly:///home/padraic');
  80. }
  81. public function testCanDetectNewRemoteVersionAndStoreVersions()
  82. {
  83. $this->updater->getStrategy()->setVersionUrl('file://' . $this->files . '/good.version');
  84. $this->assertTrue($this->updater->hasUpdate());
  85. $this->assertEquals('da39a3ee5e6b4b0d3255bfef95601890afd80709', $this->updater->getOldVersion());
  86. $this->assertEquals('1af1b9c94dea1ff337587bfa9109f1dad1ec7b9b', $this->updater->getNewVersion());
  87. }
  88. public function testThrowsExceptionOnEmptyRemoteVersion()
  89. {
  90. $this->setExpectedException(
  91. 'Humbug\\SelfUpdate\\Exception\\HttpRequestException',
  92. 'Version request returned empty response'
  93. );
  94. $this->updater->getStrategy()->setVersionUrl('file://' . $this->files . '/empty.version');
  95. $this->assertTrue($this->updater->hasUpdate());
  96. }
  97. public function testThrowsExceptionOnInvalidRemoteVersion()
  98. {
  99. $this->setExpectedException(
  100. 'Humbug\\SelfUpdate\\Exception\\HttpRequestException',
  101. 'Version request returned incorrectly formatted response'
  102. );
  103. $this->updater->getStrategy()->setVersionUrl('file://' . $this->files . '/bad.version');
  104. $this->assertTrue($this->updater->hasUpdate());
  105. }
  106. /**
  107. * @runInSeparateProcess
  108. */
  109. public function testUpdatePhar()
  110. {
  111. if (!extension_loaded('openssl')) {
  112. $this->markTestSkipped('This test requires the openssl extension to run.');
  113. }
  114. $this->createTestPharAndKey();
  115. $this->assertEquals('old', $this->getPharOutput($this->tmp . '/old.phar'));
  116. $updater = new Updater($this->tmp . '/old.phar');
  117. $updater->getStrategy()->setPharUrl('file://' . $this->files . '/build/new.phar');
  118. $updater->getStrategy()->setVersionUrl('file://' . $this->files . '/build/new.version');
  119. $this->assertTrue($updater->update());
  120. $this->assertEquals('new', $this->getPharOutput($this->tmp . '/old.phar'));
  121. }
  122. /**
  123. * @runInSeparateProcess
  124. */
  125. public function testUpdatePharFailsIfCurrentPublicKeyEmpty()
  126. {
  127. //$this->markTestSkipped('Segmentation fault at present under PHP');
  128. copy($this->files . '/build/badkey.phar', $this->tmp . '/old.phar');
  129. chmod($this->tmp . '/old.phar', 0755);
  130. copy($this->files . '/build/badkey.phar.pubkey', $this->tmp . '/old.phar.pubkey');
  131. $updater = new Updater($this->tmp . '/old.phar');
  132. $updater->getStrategy()->setPharUrl('file://' . $this->files . '/build/new.phar');
  133. $updater->getStrategy()->setVersionUrl('file://' . $this->files . '/build/new.version');
  134. $this->setExpectedException('UnexpectedValueException');
  135. $updater->update();
  136. }
  137. /**
  138. * @runInSeparateProcess
  139. */
  140. public function testUpdatePharFailsIfCurrentPublicKeyInvalid()
  141. {
  142. $this->markTestIncomplete('Segmentation fault at present under PHP');
  143. /** Should be similar to testUpdatePharFailsIfCurrentPublicKeyEmpty with
  144. corrupt or truncated public key */
  145. }
  146. /**
  147. * @runInSeparateProcess
  148. */
  149. public function testUpdatePharFailsOnExpectedSignatureMismatch()
  150. {
  151. if (!extension_loaded('openssl')) {
  152. $this->markTestSkipped('This test requires the openssl extension to run.');
  153. }
  154. $this->createTestPharAndKey();
  155. $this->assertEquals('old', $this->getPharOutput($this->tmp . '/old.phar'));
  156. /** Signature check should fail with invalid signature by a different privkey */
  157. $this->setExpectedException('UnexpectedValueException');
  158. $updater = new Updater($this->tmp . '/old.phar');
  159. $updater->getStrategy()->setPharUrl('file://' . $this->files . '/build/badsig.phar');
  160. $updater->getStrategy()->setVersionUrl('file://' . $this->files . '/build/badsig.version');
  161. $updater->update();
  162. }
  163. /**
  164. * @runInSeparateProcess
  165. */
  166. public function testUpdatePharFailsIfDownloadPharIsUnsignedWhenExpected()
  167. {
  168. $this->createTestPharAndKey();
  169. $updater = new Updater($this->tmp . '/old.phar');
  170. $updater->getStrategy()->setPharUrl('file://' . $this->files . '/build/nosig.phar');
  171. $updater->getStrategy()->setVersionUrl('file://' . $this->files . '/build/nosig.version');
  172. /** If newly download phar lacks an expected signature, an exception should be thrown */
  173. $this->setExpectedException('Humbug\\SelfUpdate\\Exception\\RuntimeException');
  174. $updater->update();
  175. }
  176. public function testSetBackupPathSetsThePathWhenTheDirectoryExistsAndIsWriteable()
  177. {
  178. $this->createTestPharAndKey();
  179. $updater = new Updater($this->tmp . '/old.phar');
  180. $updater->setBackupPath($this->tmp . '/backup.phar');
  181. $res = $updater->getBackupPath();
  182. $this->assertEquals($this->tmp . '/backup.phar', $res);
  183. }
  184. public function testSetRestorePathSetsThePathWhenTheDirectoryExistsAndIsWriteable()
  185. {
  186. $this->createTestPharAndKey();
  187. $updater = new Updater($this->tmp . '/old.phar');
  188. $updater->setRestorePath($this->tmp . '/backup.phar');
  189. $res = $updater->getRestorePath();
  190. $this->assertEquals($this->tmp . '/backup.phar', $res);
  191. }
  192. /**
  193. * Custom Strategies
  194. */
  195. public function testCanSetCustomStrategyObjects()
  196. {
  197. $this->updater->setStrategyObject(new FooStrategy);
  198. $this->assertTrue($this->updater->getStrategy() instanceof FooStrategy);
  199. }
  200. /**
  201. * Helpers
  202. */
  203. private function getPharOutput($path)
  204. {
  205. return exec('php ' . escapeshellarg($path));
  206. }
  207. private function deleteTempPhars()
  208. {
  209. @unlink($this->tmp . '/old.phar');
  210. @unlink($this->tmp . '/old.phar.pubkey');
  211. @unlink($this->tmp . '/old.1c7049180abee67826d35ce308c38272242b64b8.phar');
  212. }
  213. private function createTestPharAndKey()
  214. {
  215. copy($this->files.'/build/old.phar', $this->tmp.'/old.phar');
  216. chmod($this->tmp.'/old.phar', 0755);
  217. copy(
  218. $this->files.'/build/old.phar.pubkey',
  219. $this->tmp.'/old.phar.pubkey'
  220. );
  221. }
  222. }
  223. class FooStrategy implements StrategyInterface
  224. {
  225. public function download(Updater $updater)
  226. {
  227. }
  228. public function getCurrentRemoteVersion(Updater $updater)
  229. {
  230. }
  231. public function getCurrentLocalVersion(Updater $updater)
  232. {
  233. }
  234. }