diff --git a/.travis.yml b/.travis.yml index 094f0de0..65f28d4e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ dist: "bionic" services: - mysql + - redis-server python: - '2.7' diff --git a/appveyor.yml b/appveyor.yml index c90f027e..a8918b2f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,8 @@ build: false +before_build: + - choco install redis-64 + - redis-server --service-install + - redis-server --service-start environment: matrix: @@ -26,7 +30,7 @@ init: install: - python -m ensurepip - - pip install codecov + - pip install codecov redis - git submodule update --init --recursive # Check that we have the expected version and architecture for Python - "python --version" diff --git a/gluon/contrib/redis_session.py b/gluon/contrib/redis_session.py index 3c73bcf3..025af283 100644 --- a/gluon/contrib/redis_session.py +++ b/gluon/contrib/redis_session.py @@ -14,6 +14,7 @@ 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") @@ -71,7 +72,7 @@ class RedisClient(object): if not self.tablename: self.tablename = MockTable( self, self.r_server, tablename, self.session_expiry, - self.with_lock, fields=fields) + with_lock=self.with_lock, fields=fields) return self.tablename def __getitem__(self, key): @@ -85,6 +86,18 @@ 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 == '1' else 0, + } + for field, ftype in fields: + if field not in dict_string: + continue + typed_dict[field] = converters[ftype](dict_string[field]) if ftype in converters else dict_string[field] + return typed_dict + class MockTable(object): @@ -191,7 +204,7 @@ class MockQuery(object): rtn['update_record'] = self.update # update record support else: rtn = None - return [Storage(rtn)] if rtn else [] + return [Storage(self.db.convert_dict_string(rtn))] if rtn else [] elif self.op == 'ge' and self.field == 'id' and self.value == 0: # means that someone wants the complete list rtn = [] diff --git a/gluon/tests/test_redis.py b/gluon/tests/test_redis.py index 7b6b65f8..ed4bbaf9 100644 --- a/gluon/tests/test_redis.py +++ b/gluon/tests/test_redis.py @@ -8,7 +8,7 @@ import os import time from datetime import datetime -from gluon._compat import to_bytes +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 @@ -49,20 +49,34 @@ class TestRedis(unittest.TestCase): """ Basic redis read-write """ current = setup_clean_session() response = current.response - rconn = RConn(host='redis') + rconn = RConn(host='localhost') db = RedisSession(redis_conn=rconn, session_expiry=False) tname = 'testtablename' - db.define_table(tname) + Field = db.Field + db.define_table( + 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[tname] unique_key = web2py_uuid() dd = dict( locked=0, client_ip=response.session_client, modified_datetime=datetime.now().isoformat(), - unique_key=unique_key + 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] - print('data_from_db=', data_from_db) self.assertDictEqual(Storage(dd), data_from_db) + 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)