Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Cannot set session ID after the session has started." while testing form

I'm writing unit tests for my application. I wrote a function to login different user (to test user levels) and a function to generate valid or invalid form data (to test my form handling).

When the test submits a form, it throws an exception:

Uncaught PHP Exception LogicException: "Cannot set session ID after the session has started."

I'm using Symfony 2.6.4. I can't find any usefull information about this error message. The test worked perfectly a while ago.

class ControllerTest extends WebTestCase
{
    public $client = null;
    public $route = 'home/';

    /**
     * @var \Doctrine\ORM\EntityManager
     */
    public $em;

    public function setUp()
    {
        self::bootKernel();
        $this->client = static::createClient();

        $this->em = static::$kernel->getContainer()
            ->get('doctrine')
            ->getManager()
        ;
    }

    public function logIn($role = 'admin')
    {
        if ($role === 'admin') {
            $userId = 20;
        } elseif ($role === 'user') {
            $userId = 29;
        }
        $user = $this->em->getRepository('Acme\DemoBundle\Entity\User')->find($userId);

        $session = $this->client->getContainer()->get('session');

        $firewall = 'main';
        $token = new UsernamePasswordToken($user, $user->getPassword(), $firewall);
        $session->set('_security_'.$firewall, serialize($token));
        $session->save();

        $cookie = new Cookie($session->getName(), $session->getId());
        $this->client->getCookieJar()->set($cookie);
    }

    public function getFormData($valid = true)
    {
        //function to generate (in)valid formdata
    }

    public function getFormRequest($data, $url)
    {
        return $this->client->request(
            'POST',
            $url,
            $data,
            [],
            [
                'CONTENT_TYPE'          => 'application/json',
                'HTTP_X-Requested-With' => 'XMLHttpRequest',
            ]
        );
    }

    //works OK
    public function testNewScenario()
    {
        $url = $this->baseurl . 'new';
        $this->logIn('admin');

        $crawler = $this->client->request('GET', $url);
        $this->assertEquals(200, $this->client->getResponse()->getStatusCode(), "Unexpected HTTP status code for GET " . $url);
    }

    public function testValidNewScenario()
    {
        $this->logIn('admin');

        $validData = $this->getFormData(true);

        //this function throws the exception
        $this->getFormRequest($validData, $this->baseurl);

        $this->assertEquals(200, $this->client->getResponse()->getStatusCode(), "Unexpected HTTP status code for POST " . $this->baseurl);
    }

}

Here's the relevant part of my config_test.yml:

framework:
    test: ~
    session:
        storage_id: session.storage.mock_file
    profiler:
        collect: false

What's going on?

like image 924
Stephan Vierkant Avatar asked Oct 31 '22 11:10

Stephan Vierkant


1 Answers

I don't know if this is still a problem for the OP as this is an old post, but the same issue had me running around in circles for best part of 3 hours trying to find a way out of it. And seeing as there doesnt seem to be a solution anywhere at all. Heres a possible one.

The problem exists in tests which are trying to create a full login.

Current symfony docs state that its preferred to use basic_http authentication in your tests, but if, like me, you need to be testing access levels youll need to be following this method.

The problem seems to occur when we try to set the cookieJar up. This (for me) always threw an error.

Cannot set session ID after the session has started

the solution as it turns out is reasonably simple. Wrap the cookie set code in a condition that checks for a current session id.

if( !$this->session->getId() ) { 
      $this->cookie = new Cookie( $this->session->getName(), $this->session->getId() );
      $this->client->getCookieJar()->set( $this->cookie ); // <--- this is the problem line
}

its also worth noting that calling $this->session->invalidate() does not solve the issue.

I hope this helps someone and saves them some time.

This effected me on Symfony2.1 (no chance of upgrading), but Ive seen mentions of 2.6 getting it when combined with FOSFacebookBundle (where I believe the issue was fixed).

like image 68
DevDonkey Avatar answered Nov 13 '22 00:11

DevDonkey