Merge "rdbms: avoid LoadBalancer::getConnection waste when using $groups"
[lhc/web/wiklou.git] / tests / phpunit / includes / session / SessionProviderTest.php
1 <?php
2
3 namespace MediaWiki\Session;
4
5 use MediaWikiTestCase;
6 use Wikimedia\TestingAccessWrapper;
7
8 /**
9 * @group Session
10 * @group Database
11 * @covers MediaWiki\Session\SessionProvider
12 */
13 class SessionProviderTest extends MediaWikiTestCase {
14
15 public function testBasics() {
16 $manager = new SessionManager();
17 $logger = new \TestLogger();
18 $config = new \HashConfig();
19
20 $provider = $this->getMockForAbstractClass( SessionProvider::class );
21 $priv = TestingAccessWrapper::newFromObject( $provider );
22
23 $provider->setConfig( $config );
24 $this->assertSame( $config, $priv->config );
25 $provider->setLogger( $logger );
26 $this->assertSame( $logger, $priv->logger );
27 $provider->setManager( $manager );
28 $this->assertSame( $manager, $priv->manager );
29 $this->assertSame( $manager, $provider->getManager() );
30
31 $provider->invalidateSessionsForUser( new \User );
32
33 $this->assertSame( [], $provider->getVaryHeaders() );
34 $this->assertSame( [], $provider->getVaryCookies() );
35 $this->assertSame( null, $provider->suggestLoginUsername( new \FauxRequest ) );
36
37 $this->assertSame( get_class( $provider ), (string)$provider );
38
39 $this->assertNull( $provider->getRememberUserDuration() );
40
41 $this->assertNull( $provider->whyNoSession() );
42
43 $info = new SessionInfo( SessionInfo::MIN_PRIORITY, [
44 'id' => 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
45 'provider' => $provider,
46 ] );
47 $metadata = [ 'foo' ];
48 $this->assertTrue( $provider->refreshSessionInfo( $info, new \FauxRequest, $metadata ) );
49 $this->assertSame( [ 'foo' ], $metadata );
50 }
51
52 /**
53 * @dataProvider provideNewSessionInfo
54 * @param bool $persistId Return value for ->persistsSessionId()
55 * @param bool $persistUser Return value for ->persistsSessionUser()
56 * @param bool $ok Whether a SessionInfo is provided
57 */
58 public function testNewSessionInfo( $persistId, $persistUser, $ok ) {
59 $manager = new SessionManager();
60
61 $provider = $this->getMockBuilder( SessionProvider::class )
62 ->setMethods( [ 'canChangeUser', 'persistsSessionId' ] )
63 ->getMockForAbstractClass();
64 $provider->expects( $this->any() )->method( 'persistsSessionId' )
65 ->will( $this->returnValue( $persistId ) );
66 $provider->expects( $this->any() )->method( 'canChangeUser' )
67 ->will( $this->returnValue( $persistUser ) );
68 $provider->setManager( $manager );
69
70 if ( $ok ) {
71 $info = $provider->newSessionInfo();
72 $this->assertNotNull( $info );
73 $this->assertFalse( $info->wasPersisted() );
74 $this->assertTrue( $info->isIdSafe() );
75
76 $id = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
77 $info = $provider->newSessionInfo( $id );
78 $this->assertNotNull( $info );
79 $this->assertSame( $id, $info->getId() );
80 $this->assertFalse( $info->wasPersisted() );
81 $this->assertTrue( $info->isIdSafe() );
82 } else {
83 $this->assertNull( $provider->newSessionInfo() );
84 }
85 }
86
87 public function testMergeMetadata() {
88 $provider = $this->getMockBuilder( SessionProvider::class )
89 ->getMockForAbstractClass();
90
91 try {
92 $provider->mergeMetadata(
93 [ 'foo' => 1, 'baz' => 3 ],
94 [ 'bar' => 2, 'baz' => '3' ]
95 );
96 $this->fail( 'Expected exception not thrown' );
97 } catch ( MetadataMergeException $ex ) {
98 $this->assertSame( 'Key "baz" changed', $ex->getMessage() );
99 $this->assertSame(
100 [ 'old_value' => 3, 'new_value' => '3' ], $ex->getContext() );
101 }
102
103 $res = $provider->mergeMetadata(
104 [ 'foo' => 1, 'baz' => 3 ],
105 [ 'bar' => 2, 'baz' => 3 ]
106 );
107 $this->assertSame( [ 'bar' => 2, 'baz' => 3 ], $res );
108 }
109
110 public static function provideNewSessionInfo() {
111 return [
112 [ false, false, false ],
113 [ true, false, false ],
114 [ false, true, false ],
115 [ true, true, true ],
116 ];
117 }
118
119 public function testImmutableSessions() {
120 $provider = $this->getMockBuilder( SessionProvider::class )
121 ->setMethods( [ 'canChangeUser', 'persistsSessionId' ] )
122 ->getMockForAbstractClass();
123 $provider->expects( $this->any() )->method( 'canChangeUser' )
124 ->will( $this->returnValue( true ) );
125 $provider->preventSessionsForUser( 'Foo' );
126
127 $provider = $this->getMockBuilder( SessionProvider::class )
128 ->setMethods( [ 'canChangeUser', 'persistsSessionId' ] )
129 ->getMockForAbstractClass();
130 $provider->expects( $this->any() )->method( 'canChangeUser' )
131 ->will( $this->returnValue( false ) );
132 try {
133 $provider->preventSessionsForUser( 'Foo' );
134 $this->fail( 'Expected exception not thrown' );
135 } catch ( \BadMethodCallException $ex ) {
136 $this->assertSame(
137 'MediaWiki\\Session\\SessionProvider::preventSessionsForUser must be implemented ' .
138 'when canChangeUser() is false',
139 $ex->getMessage()
140 );
141 }
142 }
143
144 public function testHashToSessionId() {
145 $config = new \HashConfig( [
146 'SecretKey' => 'Shhh!',
147 ] );
148
149 $provider = $this->getMockForAbstractClass( SessionProvider::class,
150 [], 'MockSessionProvider' );
151 $provider->setConfig( $config );
152 $priv = TestingAccessWrapper::newFromObject( $provider );
153
154 $this->assertSame( 'eoq8cb1mg7j30ui5qolafps4hg29k5bb', $priv->hashToSessionId( 'foobar' ) );
155 $this->assertSame( '4do8j7tfld1g8tte9jqp3csfgmulaun9',
156 $priv->hashToSessionId( 'foobar', 'secret' ) );
157
158 try {
159 $priv->hashToSessionId( [] );
160 $this->fail( 'Expected exception not thrown' );
161 } catch ( \InvalidArgumentException $ex ) {
162 $this->assertSame(
163 '$data must be a string, array was passed',
164 $ex->getMessage()
165 );
166 }
167 try {
168 $priv->hashToSessionId( '', false );
169 $this->fail( 'Expected exception not thrown' );
170 } catch ( \InvalidArgumentException $ex ) {
171 $this->assertSame(
172 '$key must be a string or null, boolean was passed',
173 $ex->getMessage()
174 );
175 }
176 }
177
178 public function testDescribe() {
179 $provider = $this->getMockForAbstractClass( SessionProvider::class,
180 [], 'MockSessionProvider' );
181
182 $this->assertSame(
183 'MockSessionProvider sessions',
184 $provider->describe( \Language::factory( 'en' ) )
185 );
186 }
187
188 public function testGetAllowedUserRights() {
189 $provider = $this->getMockForAbstractClass( SessionProvider::class );
190 $backend = TestUtils::getDummySessionBackend();
191
192 try {
193 $provider->getAllowedUserRights( $backend );
194 $this->fail( 'Expected exception not thrown' );
195 } catch ( \InvalidArgumentException $ex ) {
196 $this->assertSame(
197 'Backend\'s provider isn\'t $this',
198 $ex->getMessage()
199 );
200 }
201
202 TestingAccessWrapper::newFromObject( $backend )->provider = $provider;
203 $this->assertNull( $provider->getAllowedUserRights( $backend ) );
204 }
205
206 }