Compare commits

..

2 Commits

Author SHA1 Message Date
81a052f94a Merge remote-tracking branch 'remotes/oficial/master' into patch-2 2019-12-18 16:13:59 +00:00
Dinis
3741fe4c66 initialize env with abspath
When running scripts, the path used is relative to the web2py root instead of the full path. This causes differences in migrations when using InDBMigrator - this causes pydal to try to repeat migrations already done.
2019-07-25 17:03:01 +01:00
6 changed files with 11 additions and 125 deletions

View File

@@ -6,7 +6,6 @@ dist: "bionic"
services:
- mysql
- redis-server
python:
- '2.7'
@@ -24,7 +23,6 @@ install:
before_script:
- pip install coverage
- pip install codecov
- pip install redis
before_install:
- mysql -e 'create database pydal;'

View File

@@ -1,8 +1,4 @@
build: false
before_build:
- choco install redis-64
- redis-server --service-install
- redis-server --service-start
environment:
matrix:
@@ -30,7 +26,7 @@ init:
install:
- python -m ensurepip
- pip install codecov redis
- pip install codecov
- git submodule update --init --recursive
# Check that we have the expected version and architecture for Python
- "python --version"

View File

@@ -14,7 +14,6 @@ from gluon.storage import Storage
from gluon.contrib.redis_utils import acquire_lock, release_lock
from gluon.contrib.redis_utils import register_release_lock
from gluon._compat import to_native
from datetime import datetime
logger = logging.getLogger("web2py.session.redis")
@@ -66,13 +65,13 @@ class RedisClient(object):
def Field(self, fieldname, type='string', length=None, default=None,
required=False, requires=None):
return fieldname, type
return None
def define_table(self, tablename, *fields, **args):
if not self.tablename:
self.tablename = MockTable(
self, self.r_server, tablename, self.session_expiry,
with_lock=self.with_lock, fields=fields)
self.with_lock)
return self.tablename
def __getitem__(self, key):
@@ -86,26 +85,10 @@ class RedisClient(object):
# this is only called by session2trash.py
pass
def convert_dict_string(self, dict_string):
fields = self.tablename.fields
typed_dict = dict()
converters = {
'boolean': lambda x: 1 if x.decode() == '1' else 0,
'blob': lambda x: x,
}
for field, ftype in fields:
if field not in dict_string:
continue
if ftype in converters:
typed_dict[field] = converters[ftype](dict_string[field])
else:
typed_dict[field] = dict_string[field].decode()
return typed_dict
class MockTable(object):
def __init__(self, db, r_server, tablename, session_expiry, with_lock=False, fields=None):
def __init__(self, db, r_server, tablename, session_expiry, with_lock=False):
# here self.db is the RedisClient instance
self.db = db
self.tablename = tablename
@@ -118,7 +101,6 @@ class MockTable(object):
# remember the session_expiry setting
self.session_expiry = session_expiry
self.with_lock = with_lock
self.fields = fields if fields is not None else []
def __call__(self, record_id, unique_key=None):
# Support DAL shortcut query: table(record_id)
@@ -190,11 +172,7 @@ class MockQuery(object):
self.value = value
self.op = op
def __ge__(self, value, op='ge'):
self.value = value
self.op = op
def __gt__(self, value, op='gt'):
def __gt__(self, value, op='ge'):
self.value = value
self.op = op
@@ -204,7 +182,7 @@ class MockQuery(object):
key = self.keyprefix + ':' + str(self.value)
if self.with_lock:
acquire_lock(self.db.r_server, key + ':lock', self.value, 2)
rtn = {to_native(k): v for k, v in self.db.r_server.hgetall(key).items()}
rtn = {to_native(k.decode): v for k, v in self.db.r_server.hgetall(key).items()}
if rtn:
if self.unique_key:
# make sure the id and unique_key are correct
@@ -212,8 +190,8 @@ class MockQuery(object):
rtn['update_record'] = self.update # update record support
else:
rtn = None
return [Storage(self.db.convert_dict_string(rtn))] if rtn else []
elif self.op in ('ge', 'gt') and self.field == 'id' and self.value == 0:
return [Storage(rtn)] if rtn else []
elif self.op == 'ge' and self.field == 'id' and self.value == 0:
# means that someone wants the complete list
rtn = []
id_idx = "%s:id_idx" % self.keyprefix
@@ -226,7 +204,7 @@ class MockQuery(object):
# clean up the idx, because the key expired
self.db.r_server.srem(id_idx, sess)
continue
val = Storage(self.db.convert_dict_string(val))
val = Storage(val)
# add a delete_record method (necessary for sessions2trash.py)
val.delete_record = RecordDeleter(
self.db, sess, self.keyprefix)

View File

@@ -234,7 +234,7 @@ def run(
errmsg = 'invalid application name: %s' % appname
if not a:
die(errmsg, error_preamble=False)
adir = os.path.join('applications', a)
adir = os.path.absdir(os.path.join('applications', a))
if not os.path.exists(adir):
if not cron_job and not scheduler_job and \
@@ -273,7 +273,7 @@ def run(
if vars:
# underscore necessary because request.vars is a property
extra_request['_vars'] = vars
_env = env(a, c=c, f=f, import_models=import_models, extra_request=extra_request)
_env = env(a, c=c, f=f, import_models=import_models, extra_request=extra_request, dir=adir)
if c:
pyfile = os.path.join('applications', a, 'controllers', c + '.py')

View File

@@ -8,7 +8,6 @@ from .test_dal import *
from .test_cache import *
from .test_html import *
from .test_contribs import *
from .test_redis import *
from .test_routes import *
from .test_router import *
from .test_authapi import *

View File

@@ -1,85 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
""" Unit tests for redis """
import unittest
from datetime import datetime
from gluon._compat import to_bytes, pickle
from gluon.storage import Storage
from gluon.utils import web2py_uuid
from gluon.globals import Request, Response, Session, current
from gluon.contrib.redis_utils import RConn
from gluon.contrib.redis_session import RedisSession
from gluon.contrib.redis_cache import RedisCache
class TestRedis(unittest.TestCase):
""" Tests the Redis contrib packages """
def setUp(self):
request = Request(env={})
request.application = 'a'
request.controller = 'c'
request.function = 'f'
request.folder = 'applications/admin'
response = Response()
session = Session()
session.connect(request, response)
from gluon.globals import current
current.request = request
current.response = response
current.session = session
self.current = current
rconn = RConn(host='localhost')
self.db = RedisSession(redis_conn=rconn, session_expiry=False)
self.tname = 'testtablename'
return current
def test_0_redis_session(self):
""" Basic redis read-write """
db = self.db
response = self.current.response
Field = db.Field
db.define_table(
self.tname,
Field('locked', 'boolean', default=False),
Field('client_ip', length=64),
Field('created_datetime', 'datetime',
default=datetime.now().isoformat()),
Field('modified_datetime', 'datetime'),
Field('unique_key', length=64),
Field('session_data', 'blob'),
)
table = db[self.tname]
unique_key = web2py_uuid()
dd = dict(
locked=0,
client_ip=response.session_client,
modified_datetime=datetime.now().isoformat(),
unique_key=unique_key,
session_data=pickle.dumps({'test': 123, 'me': 112312312}, pickle.HIGHEST_PROTOCOL)
)
record_id = table.insert(**dd)
data_from_db = db(table.id == record_id).select()[0]
self.assertDictEqual(Storage(dd), data_from_db, 'get inserted dict')
dd['locked'] = 1
table._db(table.id == record_id).update(**dd)
data_from_db = db(table.id == record_id).select()[0]
self.assertDictEqual(Storage(dd), data_from_db, 'get the updated value')
def test_1_redis_delete(self):
""" Redis session get and delete sessions """
db = self.db
table = db[self.tname]
all_sessions = db(table.id > 0).select()
self.assertIsNotNone(all_sessions, 'we must have some keys in db')
for entry in all_sessions:
res = entry.delete_record()
self.assertIsNone(res, 'delete should return None')
empty_sessions = db(table.id > 0).select()
self.assertEqual(empty_sessions, [], 'no sessions left')