Search code examples
google-app-enginegoogle-cloud-platformgoogle-cloud-datastoregoogle-app-engine-python

Testing a GAE handler with a fake logged in user


I have a working site on GAE, and in order to keep it that way I'm trying to add some unit tests.

One of the first things I'd like is a basic smoke test that confirms an authenticated user can load the home page. Here's my attempt:

import webtest
import unittest
from google.appengine.api import users
from google.appengine.datastore import datastore_stub_util 
from google.appengine.ext import ndb
from google.appengine.ext import testbed

# Handler under test
import main
from common import User

class MainTestCase(unittest.TestCase):
    def setUp(self):
        self.testbed = testbed.Testbed()
        self.testbed.activate()
        self.testbed.init_user_stub()
        self.policy = datastore_stub_util.PseudoRandomHRConsistencyPolicy(
            probability=0)
        self.testbed.init_datastore_v3_stub(consistency_policy=self.policy)
        self.testbed.init_memcache_stub()
        ndb.get_context().clear_cache()

    def tearDown(self):
        self.testbed.deactivate()

    def loginUser(self, email='[email protected]', id='123', is_admin=False):
        self.testbed.setup_env(
            user_email=email, user_id=id,
            user_is_admin='1' if is_admin else '0',
            overwrite=True)

    def testMainHandler(self):
        User(user_email='[email protected]', is_admin = False).put()
        self.loginUser(email='[email protected]')
        self.testapp = webtest.TestApp(main.app)
        response = self.testapp.get('/')
        self.assertEqual(response.status_int, 200)

When I run this test, I'm getting a 403 instead of a 200 and (with a little digging) the logged error that "[email protected] is not registered". The relevant bit of main.py is here:

try:
    active_email = users.get_current_user().email()
    user_acl = User.query(User.user_email == active_email).fetch(1)[0]
    security['user_exists'] = True
except IndexError:
    security['user_exists'] = False
    return security

My suspicion is that I'm setting the user correctly (as evidenced by the logged eror) but when main.py runs that User.query, it's hitting the "real" (empty, during testing) datastore instead of the fake testbed version where I've inserted the test user.

Does this sound right? Any tips on how to do this better?


Solution

  • Your query User.query(User.user_email == active_email).fetch(1) is eventually consistent, so the results of the put() may not show up immediately. Compounding this, you have self.policy = datastore_stub_util.PseudoRandomHRConsistencyPolicy( probability=0) which causes the datastore emulator to be very inconsistent. You probably want to consider changing your query to be strongly consistent or trying Cloud Firestore in Datastore mode.

    For your test, you can set probability=1.0 to see if the problem is an eventually consistent query or not.