Passed
Pull Request — 4.2 (#8269)
by Ingo
07:01
created

SessionTest::testRequestContainsSessionId()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 0
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\Control\Tests;
4
5
use http\Exception\BadMessageException;
6
use SilverStripe\Control\Cookie;
7
use SilverStripe\Control\Session;
8
use SilverStripe\Dev\SapphireTest;
9
use SilverStripe\Control\HTTPRequest;
10
11
/**
12
 * Tests to cover the {@link Session} class
13
 */
14
class SessionTest extends SapphireTest
15
{
16
    /**
17
     * @var Session
18
     */
19
    protected $session = null;
20
21
    protected function setUp()
22
    {
23
        $this->session = new Session([]);
24
        return parent::setUp();
25
    }
26
27
    /**
28
     * @runInSeparateProcess
29
     * @preserveGlobalState disabled
30
     */
31
    public function testInitDoesNotStartSessionWithoutIdentifier()
32
    {
33
        $req = new HTTPRequest('GET', '/');
34
        $session = new Session(null); // unstarted session
35
        $session->init($req);
36
        $this->assertFalse($session->isStarted());
37
    }
38
39
    /**
40
     * @runInSeparateProcess
41
     * @preserveGlobalState disabled
42
     */
43
    public function testInitStartsSessionWithIdentifier()
44
    {
45
        $req = new HTTPRequest('GET', '/');
46
        Cookie::set(session_name(), '1234');
47
        $session = new Session(null); // unstarted session
48
        $session->init($req);
49
        $this->assertTrue($session->isStarted());
50
    }
51
52
    /**
53
     * @runInSeparateProcess
54
     * @preserveGlobalState disabled
55
     */
56
    public function testInitStartsSessionWithData()
57
    {
58
        $req = new HTTPRequest('GET', '/');
59
        $session = new Session([]);
60
        $session->init($req);
61
        $this->assertTrue($session->isStarted());
62
    }
63
64
    /**
65
     * @runInSeparateProcess
66
     * @preserveGlobalState disabled
67
     */
68
    public function testStartUsesDefaultCookieNameWithHttp()
69
    {
70
        $req = (new HTTPRequest('GET', '/'))
71
            ->setScheme('http');
72
        Cookie::set(session_name(), '1234');
73
        $session = new Session(null); // unstarted session
74
        $session->start($req);
75
        $this->assertNotEquals(session_name(), $session->config()->get('cookie_name_secure'));
76
    }
77
78
    /**
79
     * @runInSeparateProcess
80
     * @preserveGlobalState disabled
81
     */
82
    public function testStartUsesDefaultCookieNameWithHttpsAndCookieSecureOff()
83
    {
84
        $req = (new HTTPRequest('GET', '/'))
85
            ->setScheme('https');
86
        Cookie::set(session_name(), '1234');
87
        $session = new Session(null); // unstarted session
88
        $session->start($req);
89
        $this->assertNotEquals(session_name(), $session->config()->get('cookie_name_secure'));
90
    }
91
92
    /**
93
     * @runInSeparateProcess
94
     * @preserveGlobalState disabled
95
     */
96
    public function testStartUsesSecureCookieNameWithHttpsAndCookieSecureOn()
97
    {
98
        $req = (new HTTPRequest('GET', '/'))
99
            ->setScheme('https');
100
        Cookie::set(session_name(), '1234');
101
        $session = new Session(null); // unstarted session
102
        $session->config()->update('cookie_secure', true);
103
        $session->start($req);
104
        $this->assertEquals(session_name(), $session->config()->get('cookie_name_secure'));
105
    }
106
107
    /**
108
     * @runInSeparateProcess
109
     * @preserveGlobalState disabled
110
     * @expectedException BadMethodCallException
111
     * @expectedExceptionMessage Session has already started
112
     */
113
    public function testStartErrorsWhenStartingTwice()
114
    {
115
        $req = new HTTPRequest('GET', '/');
116
        $session = new Session(null); // unstarted session
117
        $session->start($req);
118
        $session->start($req);
119
    }
120
121
    /**
122
     * @runInSeparateProcess
123
     * @preserveGlobalState disabled
124
     */
125
    public function testStartRetainsInMemoryData()
126
    {
127
        $this->markTestIncomplete('Test');
128
        // TODO Figure out how to simulate session vars without a session_start() resetting them
129
        // $_SESSION['existing'] = true;
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
130
        // $_SESSION['merge'] = 1;
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
131
        $req = new HTTPRequest('GET', '/');
132
        $session = new Session(null); // unstarted session
133
        $session->set('new', true);
134
        $session->set('merge', 2);
135
        $session->start($req); // simulate lazy start
136
        $this->assertEquals(
137
            [
138
                // 'existing' => true,
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
139
                'new' => true,
140
                'merge' => 2
141
            ],
142
            $session->getAll()
143
        );
144
145
        unset($_SESSION);
146
    }
147
148
    public function testGetSetBasics()
149
    {
150
        $this->session->set('Test', 'Test');
151
152
        $this->assertEquals($this->session->get('Test'), 'Test');
153
    }
154
155
    public function testClearElement()
156
    {
157
        $this->session->set('Test', 'Test');
158
        $this->session->clear('Test');
159
160
        $this->assertEquals($this->session->get('Test'), '');
161
    }
162
163
    public function testClearAllElements()
164
    {
165
        $this->session->set('Test', 'Test');
166
        $this->session->set('Test-1', 'Test-1');
167
168
        $this->session->clearAll();
169
170
        // should session get return null? The array key should probably be
171
        // unset from the data array
172
        $this->assertEquals($this->session->get('Test'), '');
173
        $this->assertEquals($this->session->get('Test-1'), '');
174
    }
175
176
    public function testGetAllElements()
177
    {
178
        $this->session->clearAll(); // Remove all session that might've been set by the test harness
179
180
        $this->session->set('Test', 'Test');
181
        $this->session->set('Test-2', 'Test-2');
182
183
        $session = $this->session->getAll();
184
        unset($session['HTTP_USER_AGENT']);
185
186
        $this->assertEquals($session, array('Test' => 'Test', 'Test-2' => 'Test-2'));
187
    }
188
189
    public function testSettingExistingDoesntClear()
190
    {
191
        $s = new Session(array('something' => array('does' => 'exist')));
192
193
        $s->set('something.does', 'exist');
194
        $result = $s->changedData();
195
        unset($result['HTTP_USER_AGENT']);
196
        $this->assertEquals(array(), $result);
197
    }
198
199
    /**
200
     * Check that changedData isn't populated with junk when clearing non-existent entries.
201
     */
202
    public function testClearElementThatDoesntExist()
203
    {
204
        $s = new Session(['something' => ['does' => 'exist']]);
205
        $s->clear('something.doesnt.exist');
206
207
        // Clear without existing data
208
        $data = $s->get('something.doesnt.exist');
209
        $this->assertEquals(array(), $s->changedData());
210
        $this->assertNull($data);
211
212
        // Clear with existing change
213
        $s->set('something-else', 'val');
214
        $s->clear('something-new');
215
        $data = $s->get('something-else');
216
        $this->assertEquals(['something-else' => true], $s->changedData());
217
        $this->assertEquals('val', $data);
218
    }
219
220
    /**
221
     * Check that changedData is populated with clearing data.
222
     */
223
    public function testClearElementThatDoesExist()
224
    {
225
        $s = new Session(['something' => ['does' => 'exist']]);
226
227
        // Ensure keys are properly removed and not simply nullified
228
        $s->clear('something.does');
229
        $this->assertEquals(
230
            ['something' => ['does' => true]],
231
            $s->changedData()
232
        );
233
        $this->assertEquals(
234
            [], // 'does' removed
235
            $s->get('something')
236
        );
237
238
        // Clear at more specific level should also clear other changes
239
        $s->clear('something');
240
        $this->assertEquals(
241
            ['something' => true],
242
            $s->changedData()
243
        );
244
        $this->assertEquals(
245
            null, // Should be removed not just empty array
246
            $s->get('something')
247
        );
248
    }
249
250
    public function testRequestContainsSessionId()
251
    {
252
        $req = new HTTPRequest('GET', '/');
253
        $session = new Session(null); // unstarted session
254
        $this->assertFalse($session->requestContainsSessionId($req));
255
        Cookie::set(session_name(), '1234');
256
        $this->assertTrue($session->requestContainsSessionId($req));
257
    }
258
259
    public function testRequestContainsSessionIdRespectsCookieNameSecure()
260
    {
261
        $req = (new HTTPRequest('GET', '/'))
262
            ->setScheme('https');
263
        $session = new Session(null); // unstarted session
264
        Cookie::set($session->config()->get('cookie_name_secure'), '1234');
265
        $session->config()->update('cookie_secure', true);
266
        $this->assertTrue($session->requestContainsSessionId($req));
267
    }
268
269
    public function testUserAgentLockout()
270
    {
271
        // Set a user agent
272
        $req1 = new HTTPRequest('GET', '/');
273
        $req1->addHeader('User-Agent', 'Test Agent');
274
275
        // Generate our session
276
        $s = new Session(array());
277
        $s->init($req1);
278
        $s->set('val', 123);
279
        $s->finalize($req1);
280
281
        // Change our UA
282
        $req2 = new HTTPRequest('GET', '/');
283
        $req2->addHeader('User-Agent', 'Fake Agent');
284
285
        // Verify the new session reset our values
286
        $s2 = new Session($s);
287
        $s2->init($req2);
288
        $this->assertNotEquals($s2->get('val'), 123);
289
    }
290
291
    public function testSave()
292
    {
293
        $request = new HTTPRequest('GET', '/');
294
295
        // Test change of nested array type
296
        $s = new Session($_SESSION = ['something' => ['some' => 'value', 'another' => 'item']]);
297
        $s->set('something', 'string');
298
        $s->save($request);
299
        $this->assertEquals(
300
            ['something' => 'string'],
301
            $_SESSION
302
        );
303
304
        // Test multiple changes combine safely
305
        $s = new Session($_SESSION = ['something' => ['some' => 'value', 'another' => 'item']]);
306
        $s->set('something.another', 'newanother');
307
        $s->clear('something.some');
308
        $s->set('something.newkey', 'new value');
309
        $s->save($request);
310
        $this->assertEquals(
311
            [
312
                'something' => [
313
                    'another' => 'newanother',
314
                    'newkey' => 'new value',
315
                ]
316
            ],
317
            $_SESSION
318
        );
319
320
        // Test cleared keys are restorable
321
        $s = new Session($_SESSION = ['bookmarks' => [ 1 => 1, 2 => 2]]);
322
        $s->clear('bookmarks');
323
        $s->set('bookmarks', [
324
            1 => 1,
325
            3 => 3,
326
        ]);
327
        $s->save($request);
328
        $this->assertEquals(
329
            [
330
                'bookmarks' => [
331
                    1 => 1,
332
                    3 => 3,
333
                ]
334
            ],
335
            $_SESSION
336
        );
337
    }
338
}
339