goa/testlib.py
changeset 6366 1806148d6ce8
parent 6333 e3994fcc21c3
parent 6365 a15cc5e16178
child 6367 d4c485ec1ca1
equal deleted inserted replaced
6333:e3994fcc21c3 6366:1806148d6ce8
     1 # copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
       
     2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
       
     3 #
       
     4 # This file is part of CubicWeb.
       
     5 #
       
     6 # CubicWeb is free software: you can redistribute it and/or modify it under the
       
     7 # terms of the GNU Lesser General Public License as published by the Free
       
     8 # Software Foundation, either version 2.1 of the License, or (at your option)
       
     9 # any later version.
       
    10 #
       
    11 # CubicWeb is distributed in the hope that it will be useful, but WITHOUT
       
    12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
       
    13 # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
       
    14 # details.
       
    15 #
       
    16 # You should have received a copy of the GNU Lesser General Public License along
       
    17 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
       
    18 """
       
    19 """
       
    20 __docformat__ = "restructuredtext en"
       
    21 
       
    22 from logilab.common.testlib import TestCase, TestSkipped
       
    23 try:
       
    24     import google.appengine
       
    25 except ImportError:
       
    26     raise TestSkipped('Can not import google.appengine. Skip this module')
       
    27 
       
    28 import os, os.path as osp
       
    29 import time
       
    30 from shutil import copy
       
    31 
       
    32 # additional monkey patches necessary in regular cubicweb environment
       
    33 from cubicweb.server import rqlannotation
       
    34 from cubicweb.goa.overrides import rqlannotation as goarqlannotation
       
    35 rqlannotation.SQLGenAnnotator = goarqlannotation.SQLGenAnnotator
       
    36 rqlannotation.set_qdata = goarqlannotation.set_qdata
       
    37 
       
    38 from google.appengine.api import apiproxy_stub_map
       
    39 from google.appengine.api import datastore_file_stub
       
    40 from google.appengine.ext import db as gdb
       
    41 
       
    42 from cubicweb.devtools.fake import FakeRequest
       
    43 
       
    44 from cubicweb.goa import db, do_monkey_patch
       
    45 from cubicweb.goa.goavreg import GAEVRegistry
       
    46 from cubicweb.goa.goaconfig import GAEConfiguration
       
    47 from cubicweb.goa.dbinit import (create_user, create_groups, fix_entities,
       
    48                                  init_persistent_schema, insert_versions)
       
    49 
       
    50 import logging
       
    51 logger = logging.getLogger()
       
    52 logger.setLevel(logging.CRITICAL)
       
    53 
       
    54 do_monkey_patch()
       
    55 
       
    56 class GAEBasedTC(TestCase):
       
    57     APP_ID = u'test_app'
       
    58     AUTH_DOMAIN = 'gmail.com'
       
    59     LOGGED_IN_USER = u't...@example.com'  # set to '' for no logged in user
       
    60     MODEL_CLASSES = None
       
    61     LOAD_APP_MODULES = None
       
    62     config = None
       
    63     _DS_TEMPL_FILE = 'tmpdb-template'
       
    64 
       
    65     def load_schema_hook(self, loader):
       
    66         loader.import_yams_cube_schema('data')
       
    67 
       
    68     @property
       
    69     def DS_FILE(self):
       
    70         return self.DS_TEMPL_FILE.replace('-template', '')
       
    71 
       
    72     @property
       
    73     def DS_TEMPL_FILE(self):
       
    74         return self._DS_TEMPL_FILE + '_'.join(sorted(cls.__name__ for cls in self.MODEL_CLASSES))
       
    75 
       
    76     def _set_ds_file(self, dsfile):
       
    77         # Start with a fresh api proxy.
       
    78         apiproxy_stub_map.apiproxy = apiproxy_stub_map.APIProxyStubMap()
       
    79         # Use a fresh stub datastore.
       
    80         stub = datastore_file_stub.DatastoreFileStub(self.APP_ID, dsfile,
       
    81                                                      dsfile+'.history')
       
    82         apiproxy_stub_map.apiproxy.RegisterStub('datastore_v3', stub)
       
    83 
       
    84     def setUp(self):
       
    85         # Ensure we're in UTC.
       
    86         os.environ['TZ'] = 'UTC'
       
    87         time.tzset()
       
    88         if osp.exists(self.DS_TEMPL_FILE):
       
    89             copy(self.DS_TEMPL_FILE, self.DS_FILE)
       
    90             need_ds_init = False
       
    91             self._set_ds_file(self.DS_FILE)
       
    92         else:
       
    93             need_ds_init = True
       
    94             self._set_ds_file(self.DS_TEMPL_FILE)
       
    95 #         from google.appengine.api import mail_stub
       
    96 #         from google3.apphosting.api import urlfetch_stub
       
    97 #         from google3.apphosting.api import user_service_stub
       
    98 #         # Use a fresh stub UserService.
       
    99 #         apiproxy_stub_map.apiproxy.RegisterStub(
       
   100 #             'user', user_service_stub.UserServiceStub())
       
   101         os.environ['AUTH_DOMAIN'] = self.AUTH_DOMAIN
       
   102         os.environ['USER_EMAIL'] = self.LOGGED_IN_USER
       
   103 #         # Use a fresh urlfetch stub.
       
   104 #         apiproxy_stub_map.apiproxy.RegisterStub(
       
   105 #             'urlfetch', urlfetch_stub.URLFetchServiceStub())
       
   106 #         # Use a fresh mail stub.
       
   107 #         apiproxy_stub_map.apiproxy.RegisterStub(
       
   108 #             'mail', mail_stub.MailServiceStub())
       
   109         if self.MODEL_CLASSES is None:
       
   110             raise Exception('GAEBasedTC should set MODEL_CLASSES class attribute')
       
   111         gdb._kind_map = {}
       
   112         self.config = self.config or GAEConfiguration('toto')
       
   113         self.config.init_log(logging.CRITICAL)
       
   114         self.schema = self.config.load_schema(self.MODEL_CLASSES,
       
   115                                               self.load_schema_hook)
       
   116         self.vreg = GAEVregistry(self.config)
       
   117         self.vreg.schema = self.schema
       
   118         self.vreg.load_module(db)
       
   119         from cubicweb.goa.appobjects import sessions
       
   120         self.vreg.load_module(sessions)
       
   121         from cubicweb.entities import authobjs, schemaobjs
       
   122         self.vreg.load_module(authobjs)
       
   123         self.vreg.load_module(schemaobjs)
       
   124         if self.config['use-google-auth']:
       
   125             from cubicweb.goa.appobjects import gauthservice
       
   126             self.vreg.load_module(gauthservice)
       
   127         if self.LOAD_APP_MODULES is not None:
       
   128             for module in self.LOAD_APP_MODULES:
       
   129                 self.vreg.load_module(module)
       
   130         for cls in self.MODEL_CLASSES:
       
   131             self.vreg.register(cls)
       
   132         self.session_manager = self.vreg.select('components', 'sessionmanager')
       
   133         if need_ds_init:
       
   134             # create default groups and create entities according to the schema
       
   135             create_groups()
       
   136             if not self.config['use-google-auth']:
       
   137                 create_user(self.LOGGED_IN_USER, 'toto', ('users', 'managers'))
       
   138                 self.session = self.login(self.LOGGED_IN_USER, 'toto')
       
   139             else:
       
   140                 req = FakeRequest(vreg=self.vreg)
       
   141                 self.session = self.session_manager.open_session(req)
       
   142             self.user = self.session.user()
       
   143             ssession = self.config.repo_session(self.session.sessionid)
       
   144             ssession.set_pool()
       
   145             init_persistent_schema(ssession, self.schema)
       
   146             insert_versions(ssession, self.config)
       
   147             ssession.commit()
       
   148             fix_entities(self.schema)
       
   149             copy(self.DS_TEMPL_FILE, self.DS_FILE)
       
   150             self._set_ds_file(self.DS_FILE)
       
   151         else:
       
   152             if not self.config['use-google-auth']:
       
   153                 self.session = self.login(self.LOGGED_IN_USER, 'toto')
       
   154             else:
       
   155                 req = FakeRequest(vreg=self.vreg)
       
   156                 self.session = self.session_manager.open_session(req)
       
   157             self.user = self.session.user()
       
   158 
       
   159     def tearDown(self):
       
   160         self.session.close()
       
   161 
       
   162     def request(self):
       
   163         req = FakeRequest(vreg=self.vreg)
       
   164         req.set_connection(self.session, self.user)
       
   165         return req
       
   166 
       
   167     def add_entity(self, etype, **kwargs):
       
   168         cu = self.session.cursor()
       
   169         rql = 'INSERT %s X' % etype
       
   170         if kwargs:
       
   171             rql += ': %s' % ', '.join('X %s %%(%s)s' % (key, key) for key in kwargs)
       
   172         rset = cu.execute(rql, kwargs)
       
   173         return rset.get_entity(0, 0)
       
   174 
       
   175     def execute(self, *args):
       
   176         return self.session.cursor().execute(*args)
       
   177 
       
   178     def commit(self):
       
   179         self.session.commit()
       
   180 
       
   181     def rollback(self):
       
   182         self.session.rollback()
       
   183 
       
   184     def create_user(self, login, groups=('users',), req=None):
       
   185         assert not self.config['use-google-auth']
       
   186         user = self.add_entity('CWUser', upassword=str(login), login=unicode(login))
       
   187         cu = self.session.cursor()
       
   188         cu.execute('SET X in_group G WHERE X eid %%(x)s, G name IN(%s)'
       
   189                     % ','.join(repr(g) for g in groups),
       
   190                     {'x': user.eid}, 'x')
       
   191         return user
       
   192 
       
   193     def login(self, login, password=None):
       
   194         assert not self.config['use-google-auth']
       
   195         req = FakeRequest(vreg=self.vreg)
       
   196         req.form['__login'] = login
       
   197         req.form['__password'] = password or login
       
   198         return self.session_manager.open_session(req)