SessionStoreTest.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. <?php
  2. namespace Illuminate\Tests\Session;
  3. use Illuminate\Cookie\CookieJar;
  4. use Illuminate\Session\CookieSessionHandler;
  5. use Illuminate\Session\Store;
  6. use Illuminate\Support\Str;
  7. use Mockery as m;
  8. use PHPUnit\Framework\TestCase;
  9. use ReflectionClass;
  10. use SessionHandlerInterface;
  11. use Symfony\Component\HttpFoundation\Request;
  12. class SessionStoreTest extends TestCase
  13. {
  14. protected function tearDown(): void
  15. {
  16. m::close();
  17. }
  18. public function testSessionIsLoadedFromHandler()
  19. {
  20. $session = $this->getSession();
  21. $session->getHandler()->shouldReceive('read')->once()->with($this->getSessionId())->andReturn(serialize(['foo' => 'bar', 'bagged' => ['name' => 'taylor']]));
  22. $session->start();
  23. $this->assertSame('bar', $session->get('foo'));
  24. $this->assertSame('baz', $session->get('bar', 'baz'));
  25. $this->assertTrue($session->has('foo'));
  26. $this->assertFalse($session->has('bar'));
  27. $this->assertTrue($session->isStarted());
  28. $session->put('baz', 'boom');
  29. $this->assertTrue($session->has('baz'));
  30. }
  31. public function testSessionMigration()
  32. {
  33. $session = $this->getSession();
  34. $oldId = $session->getId();
  35. $session->getHandler()->shouldReceive('destroy')->never();
  36. $this->assertTrue($session->migrate());
  37. $this->assertNotEquals($oldId, $session->getId());
  38. $session = $this->getSession();
  39. $oldId = $session->getId();
  40. $session->getHandler()->shouldReceive('destroy')->once()->with($oldId);
  41. $this->assertTrue($session->migrate(true));
  42. $this->assertNotEquals($oldId, $session->getId());
  43. }
  44. public function testSessionRegeneration()
  45. {
  46. $session = $this->getSession();
  47. $oldId = $session->getId();
  48. $session->getHandler()->shouldReceive('destroy')->never();
  49. $this->assertTrue($session->regenerate());
  50. $this->assertNotEquals($oldId, $session->getId());
  51. }
  52. public function testCantSetInvalidId()
  53. {
  54. $session = $this->getSession();
  55. $this->assertTrue($session->isValidId($session->getId()));
  56. $session->setId(null);
  57. $this->assertNotNull($session->getId());
  58. $this->assertTrue($session->isValidId($session->getId()));
  59. $session->setId(['a']);
  60. $this->assertNotSame(['a'], $session->getId());
  61. $session->setId('wrong');
  62. $this->assertNotSame('wrong', $session->getId());
  63. }
  64. public function testSessionInvalidate()
  65. {
  66. $session = $this->getSession();
  67. $oldId = $session->getId();
  68. $session->put('foo', 'bar');
  69. $this->assertGreaterThan(0, count($session->all()));
  70. $session->flash('name', 'Taylor');
  71. $this->assertTrue($session->has('name'));
  72. $session->getHandler()->shouldReceive('destroy')->once()->with($oldId);
  73. $this->assertTrue($session->invalidate());
  74. $this->assertFalse($session->has('name'));
  75. $this->assertNotEquals($oldId, $session->getId());
  76. $this->assertCount(0, $session->all());
  77. }
  78. public function testBrandNewSessionIsProperlySaved()
  79. {
  80. $session = $this->getSession();
  81. $session->getHandler()->shouldReceive('read')->once()->andReturn(serialize([]));
  82. $session->start();
  83. $session->put('foo', 'bar');
  84. $session->flash('baz', 'boom');
  85. $session->now('qux', 'norf');
  86. $session->getHandler()->shouldReceive('write')->once()->with(
  87. $this->getSessionId(),
  88. serialize([
  89. '_token' => $session->token(),
  90. 'foo' => 'bar',
  91. 'baz' => 'boom',
  92. '_flash' => [
  93. 'new' => [],
  94. 'old' => ['baz'],
  95. ],
  96. ])
  97. );
  98. $session->save();
  99. $this->assertFalse($session->isStarted());
  100. }
  101. public function testSessionIsProperlyUpdated()
  102. {
  103. $session = $this->getSession();
  104. $session->getHandler()->shouldReceive('read')->once()->andReturn(serialize([
  105. '_token' => Str::random(40),
  106. 'foo' => 'bar',
  107. 'baz' => 'boom',
  108. '_flash' => [
  109. 'new' => [],
  110. 'old' => ['baz'],
  111. ],
  112. ]));
  113. $session->start();
  114. $session->getHandler()->shouldReceive('write')->once()->with(
  115. $this->getSessionId(),
  116. serialize([
  117. '_token' => $session->token(),
  118. 'foo' => 'bar',
  119. '_flash' => [
  120. 'new' => [],
  121. 'old' => [],
  122. ],
  123. ])
  124. );
  125. $session->save();
  126. $this->assertFalse($session->isStarted());
  127. }
  128. public function testSessionIsReSavedWhenNothingHasChanged()
  129. {
  130. $session = $this->getSession();
  131. $session->getHandler()->shouldReceive('read')->once()->andReturn(serialize([
  132. '_token' => Str::random(40),
  133. 'foo' => 'bar',
  134. 'baz' => 'boom',
  135. '_flash' => [
  136. 'new' => [],
  137. 'old' => [],
  138. ],
  139. ]));
  140. $session->start();
  141. $session->getHandler()->shouldReceive('write')->once()->with(
  142. $this->getSessionId(),
  143. serialize([
  144. '_token' => $session->token(),
  145. 'foo' => 'bar',
  146. 'baz' => 'boom',
  147. '_flash' => [
  148. 'new' => [],
  149. 'old' => [],
  150. ],
  151. ])
  152. );
  153. $session->save();
  154. $this->assertFalse($session->isStarted());
  155. }
  156. public function testSessionIsReSavedWhenNothingHasChangedExceptSessionId()
  157. {
  158. $session = $this->getSession();
  159. $oldId = $session->getId();
  160. $token = Str::random(40);
  161. $session->getHandler()->shouldReceive('read')->once()->with($oldId)->andReturn(serialize([
  162. '_token' => $token,
  163. 'foo' => 'bar',
  164. 'baz' => 'boom',
  165. '_flash' => [
  166. 'new' => [],
  167. 'old' => [],
  168. ],
  169. ]));
  170. $session->start();
  171. $oldId = $session->getId();
  172. $session->migrate();
  173. $newId = $session->getId();
  174. $this->assertNotEquals($newId, $oldId);
  175. $session->getHandler()->shouldReceive('write')->once()->with(
  176. $newId,
  177. serialize([
  178. '_token' => $token,
  179. 'foo' => 'bar',
  180. 'baz' => 'boom',
  181. '_flash' => [
  182. 'new' => [],
  183. 'old' => [],
  184. ],
  185. ])
  186. );
  187. $session->save();
  188. $this->assertFalse($session->isStarted());
  189. }
  190. public function testOldInputFlashing()
  191. {
  192. $session = $this->getSession();
  193. $session->put('boom', 'baz');
  194. $session->flashInput(['foo' => 'bar', 'bar' => 0]);
  195. $this->assertTrue($session->hasOldInput('foo'));
  196. $this->assertSame('bar', $session->getOldInput('foo'));
  197. $this->assertEquals(0, $session->getOldInput('bar'));
  198. $this->assertFalse($session->hasOldInput('boom'));
  199. $session->ageFlashData();
  200. $this->assertTrue($session->hasOldInput('foo'));
  201. $this->assertSame('bar', $session->getOldInput('foo'));
  202. $this->assertEquals(0, $session->getOldInput('bar'));
  203. $this->assertFalse($session->hasOldInput('boom'));
  204. }
  205. public function testDataFlashing()
  206. {
  207. $session = $this->getSession();
  208. $session->flash('foo', 'bar');
  209. $session->flash('bar', 0);
  210. $session->flash('baz');
  211. $this->assertTrue($session->has('foo'));
  212. $this->assertSame('bar', $session->get('foo'));
  213. $this->assertEquals(0, $session->get('bar'));
  214. $this->assertTrue($session->get('baz'));
  215. $session->ageFlashData();
  216. $this->assertTrue($session->has('foo'));
  217. $this->assertSame('bar', $session->get('foo'));
  218. $this->assertEquals(0, $session->get('bar'));
  219. $session->ageFlashData();
  220. $this->assertFalse($session->has('foo'));
  221. $this->assertNull($session->get('foo'));
  222. }
  223. public function testDataFlashingNow()
  224. {
  225. $session = $this->getSession();
  226. $session->now('foo', 'bar');
  227. $session->now('bar', 0);
  228. $this->assertTrue($session->has('foo'));
  229. $this->assertSame('bar', $session->get('foo'));
  230. $this->assertEquals(0, $session->get('bar'));
  231. $session->ageFlashData();
  232. $this->assertFalse($session->has('foo'));
  233. $this->assertNull($session->get('foo'));
  234. }
  235. public function testDataMergeNewFlashes()
  236. {
  237. $session = $this->getSession();
  238. $session->flash('foo', 'bar');
  239. $session->put('fu', 'baz');
  240. $session->put('_flash.old', ['qu']);
  241. $this->assertNotFalse(array_search('foo', $session->get('_flash.new')));
  242. $this->assertFalse(array_search('fu', $session->get('_flash.new')));
  243. $session->keep(['fu', 'qu']);
  244. $this->assertNotFalse(array_search('foo', $session->get('_flash.new')));
  245. $this->assertNotFalse(array_search('fu', $session->get('_flash.new')));
  246. $this->assertNotFalse(array_search('qu', $session->get('_flash.new')));
  247. $this->assertFalse(array_search('qu', $session->get('_flash.old')));
  248. }
  249. public function testReflash()
  250. {
  251. $session = $this->getSession();
  252. $session->flash('foo', 'bar');
  253. $session->put('_flash.old', ['foo']);
  254. $session->reflash();
  255. $this->assertNotFalse(array_search('foo', $session->get('_flash.new')));
  256. $this->assertFalse(array_search('foo', $session->get('_flash.old')));
  257. }
  258. public function testReflashWithNow()
  259. {
  260. $session = $this->getSession();
  261. $session->now('foo', 'bar');
  262. $session->reflash();
  263. $this->assertNotFalse(array_search('foo', $session->get('_flash.new')));
  264. $this->assertFalse(array_search('foo', $session->get('_flash.old')));
  265. }
  266. public function testOnly()
  267. {
  268. $session = $this->getSession();
  269. $session->put('foo', 'bar');
  270. $session->put('qu', 'ux');
  271. $this->assertEquals(['foo' => 'bar', 'qu' => 'ux'], $session->all());
  272. $this->assertEquals(['qu' => 'ux'], $session->only(['qu']));
  273. }
  274. public function testReplace()
  275. {
  276. $session = $this->getSession();
  277. $session->put('foo', 'bar');
  278. $session->put('qu', 'ux');
  279. $session->replace(['foo' => 'baz']);
  280. $this->assertSame('baz', $session->get('foo'));
  281. $this->assertSame('ux', $session->get('qu'));
  282. }
  283. public function testRemove()
  284. {
  285. $session = $this->getSession();
  286. $session->put('foo', 'bar');
  287. $pulled = $session->remove('foo');
  288. $this->assertFalse($session->has('foo'));
  289. $this->assertSame('bar', $pulled);
  290. }
  291. public function testClear()
  292. {
  293. $session = $this->getSession();
  294. $session->put('foo', 'bar');
  295. $session->flush();
  296. $this->assertFalse($session->has('foo'));
  297. $session->put('foo', 'bar');
  298. $session->flush();
  299. $this->assertFalse($session->has('foo'));
  300. }
  301. public function testIncrement()
  302. {
  303. $session = $this->getSession();
  304. $session->put('foo', 5);
  305. $foo = $session->increment('foo');
  306. $this->assertEquals(6, $foo);
  307. $this->assertEquals(6, $session->get('foo'));
  308. $foo = $session->increment('foo', 4);
  309. $this->assertEquals(10, $foo);
  310. $this->assertEquals(10, $session->get('foo'));
  311. $session->increment('bar');
  312. $this->assertEquals(1, $session->get('bar'));
  313. }
  314. public function testDecrement()
  315. {
  316. $session = $this->getSession();
  317. $session->put('foo', 5);
  318. $foo = $session->decrement('foo');
  319. $this->assertEquals(4, $foo);
  320. $this->assertEquals(4, $session->get('foo'));
  321. $foo = $session->decrement('foo', 4);
  322. $this->assertEquals(0, $foo);
  323. $this->assertEquals(0, $session->get('foo'));
  324. $session->decrement('bar');
  325. $this->assertEquals(-1, $session->get('bar'));
  326. }
  327. public function testHasOldInputWithoutKey()
  328. {
  329. $session = $this->getSession();
  330. $session->flash('boom', 'baz');
  331. $this->assertFalse($session->hasOldInput());
  332. $session->flashInput(['foo' => 'bar']);
  333. $this->assertTrue($session->hasOldInput());
  334. }
  335. public function testHandlerNeedsRequest()
  336. {
  337. $session = $this->getSession();
  338. $this->assertFalse($session->handlerNeedsRequest());
  339. $session->getHandler()->shouldReceive('setRequest')->never();
  340. $session = new Store('test', m::mock(new CookieSessionHandler(new CookieJar, 60)));
  341. $this->assertTrue($session->handlerNeedsRequest());
  342. $session->getHandler()->shouldReceive('setRequest')->once();
  343. $request = new Request;
  344. $session->setRequestOnHandler($request);
  345. }
  346. public function testToken()
  347. {
  348. $session = $this->getSession();
  349. $this->assertEquals($session->token(), $session->token());
  350. }
  351. public function testRegenerateToken()
  352. {
  353. $session = $this->getSession();
  354. $token = $session->token();
  355. $session->regenerateToken();
  356. $this->assertNotEquals($token, $session->token());
  357. }
  358. public function testName()
  359. {
  360. $session = $this->getSession();
  361. $this->assertEquals($session->getName(), $this->getSessionName());
  362. $session->setName('foo');
  363. $this->assertSame('foo', $session->getName());
  364. }
  365. public function testKeyExists()
  366. {
  367. $session = $this->getSession();
  368. $session->put('foo', 'bar');
  369. $this->assertTrue($session->exists('foo'));
  370. $session->put('baz', null);
  371. $session->put('hulk', ['one' => true]);
  372. $this->assertFalse($session->has('baz'));
  373. $this->assertTrue($session->exists('baz'));
  374. $this->assertFalse($session->exists('bogus'));
  375. $this->assertTrue($session->exists(['foo', 'baz']));
  376. $this->assertFalse($session->exists(['foo', 'baz', 'bogus']));
  377. $this->assertTrue($session->exists(['hulk.one']));
  378. $this->assertFalse($session->exists(['hulk.two']));
  379. }
  380. public function testKeyMissing()
  381. {
  382. $session = $this->getSession();
  383. $session->put('foo', 'bar');
  384. $this->assertFalse($session->missing('foo'));
  385. $session->put('baz', null);
  386. $session->put('hulk', ['one' => true]);
  387. $this->assertFalse($session->has('baz'));
  388. $this->assertFalse($session->missing('baz'));
  389. $this->assertTrue($session->missing('bogus'));
  390. $this->assertFalse($session->missing(['foo', 'baz']));
  391. $this->assertTrue($session->missing(['foo', 'baz', 'bogus']));
  392. $this->assertFalse($session->missing(['hulk.one']));
  393. $this->assertTrue($session->missing(['hulk.two']));
  394. }
  395. public function testRememberMethodCallsPutAndReturnsDefault()
  396. {
  397. $session = $this->getSession();
  398. $session->getHandler()->shouldReceive('get')->andReturn(null);
  399. $result = $session->remember('foo', function () {
  400. return 'bar';
  401. });
  402. $this->assertSame('bar', $session->get('foo'));
  403. $this->assertSame('bar', $result);
  404. }
  405. public function getSession()
  406. {
  407. $reflection = new ReflectionClass(Store::class);
  408. return $reflection->newInstanceArgs($this->getMocks());
  409. }
  410. public function getMocks()
  411. {
  412. return [
  413. $this->getSessionName(),
  414. m::mock(SessionHandlerInterface::class),
  415. $this->getSessionId(),
  416. ];
  417. }
  418. public function getSessionId()
  419. {
  420. return 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
  421. }
  422. public function getSessionName()
  423. {
  424. return 'name';
  425. }
  426. }