Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Started setting up the SQLAlchemy tests and mixins
- Loading branch information
Showing
14 changed files
with
206 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,4 @@ def includeme(config): | |
|
||
class SQLABackend(object): | ||
pass | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,66 @@ | ||
from sqlalchemy.ext.declarative import declared_attr | ||
from sqlalchemy.ext.hybrid import hybrid_property | ||
from horus.utils.text import generate_random_string | ||
from horus.interfaces import IUser | ||
from zope.interface import implements | ||
from cryptacular import bcrypt | ||
import sqlalchemy as sa | ||
|
||
crypt = bcrypt.BCRYPTPasswordManager() | ||
|
||
|
||
class BaseMixin(object): | ||
pass | ||
@declared_attr | ||
def id(self): | ||
return sa.Column(sa.Integer, autoincrement=True, primary_key=True) | ||
|
||
|
||
class UserMixin(BaseMixin): | ||
implements(IUser) | ||
|
||
__tablename__ = 'user' | ||
|
||
class UserMixin(object): | ||
@declared_attr | ||
def principals(self): | ||
pass | ||
def username(self): | ||
""" Unique username """ | ||
return sa.Column(sa.Unicode(30), nullable=False, unique=True) | ||
|
||
@declared_attr | ||
def date_registered(self): | ||
""" Date of user's registration """ | ||
return sa.Column( | ||
sa.TIMESTAMP(timezone=False), | ||
default=sa.sql.func.now(), | ||
server_default=sa.func.now(), | ||
nullable=False, | ||
) | ||
|
||
@declared_attr | ||
def salt(self): | ||
""" Password salt for user """ | ||
return sa.Column(sa.Unicode(256), nullable=True) | ||
|
||
class UserGroupLinkMixin(object): | ||
pass | ||
@declared_attr | ||
def _password(self): | ||
""" Password hash for user object """ | ||
return sa.Column('password', sa.Unicode(256), nullable=True) | ||
|
||
@hybrid_property | ||
def password(self): | ||
return self._password | ||
|
||
class GroupMixin(object): | ||
pass | ||
@password.setter | ||
def password(self, value): | ||
self._set_password(value) | ||
|
||
def _get_password(self): | ||
return self._password | ||
|
||
class UserRoleLinkMixin(object): | ||
pass | ||
def _set_password(self, raw_password): | ||
self._password = self._hash_password(raw_password) | ||
|
||
def _hash_password(self, password): | ||
if not self.salt: | ||
self.salt = generate_random_string(24) | ||
|
||
class RoleMixin(object): | ||
pass | ||
return unicode(crypt.encode(password + self.salt)) |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import hashlib | ||
import random | ||
import string | ||
from pyramid.compat import text_type | ||
|
||
|
||
def generate_random_string(length=12): | ||
"""Generate a generic hash key for the user to use.""" | ||
m = hashlib.sha256() | ||
word = '' | ||
for i in range(length): | ||
word += random.choice(string.ascii_letters) | ||
m.update(word.encode('ascii')) | ||
return text_type(m.hexdigest()[:length]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import pytest | ||
|
||
from sqlalchemy.ext.declarative import declarative_base | ||
from horus.backends.sqla.mixins import UserMixin | ||
|
||
BaseModel = declarative_base() | ||
|
||
|
||
class UserModel(UserMixin, BaseModel): | ||
pass | ||
|
||
|
||
@pytest.mark.sqla | ||
def test_user_class(db_session): | ||
|
||
user = UserModel(username='sontek') | ||
db_session.add(user) | ||
db_session.flush() | ||
results = db_session.query(UserModel).all() | ||
assert results[0] == user |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import pytest | ||
import os | ||
import mock | ||
|
||
from pyramid.paster import get_appsettings | ||
from pyramid import testing | ||
from sqlalchemy import engine_from_config | ||
from sqlalchemy.orm import sessionmaker | ||
|
||
here = os.path.dirname(__file__) | ||
config_file = os.path.join(here, 'test.ini') | ||
settings = get_appsettings(config_file) | ||
_DBSession = None | ||
_DBTrans = None | ||
current_session = None | ||
|
||
|
||
class NotAllowed(Exception): | ||
message = 'You must mark your test as sqla' | ||
|
||
|
||
def pytest_addoption(parser): | ||
parser.addoption( | ||
"--slow", | ||
action="store_true", | ||
help="run slow tests" | ||
) | ||
|
||
parser.addoption( | ||
"--sqla", | ||
action="store_true", | ||
help="run sqla tests" | ||
) | ||
|
||
|
||
def setup_sqlalchemy(): | ||
global DBTrans | ||
global _DBSession | ||
|
||
testing.setUp(settings=settings) | ||
|
||
engine = engine_from_config(settings, prefix='backend.sqla.') | ||
connection = engine.connect() | ||
DBTrans = connection.begin() | ||
_DBSession = sessionmaker(bind=connection)() | ||
|
||
|
||
def pytest_runtest_setup(item): | ||
global current_session | ||
current_session = None | ||
|
||
if 'slow' in item.keywords and not item.config.getoption("--slow"): | ||
pytest.skip("need --slow option to run") | ||
return | ||
|
||
if 'sqla' in item.keywords and not item.config.getoption("--sqla"): | ||
pytest.skip("need --sqla option to run") | ||
return | ||
else: | ||
current_session = _DBSession | ||
|
||
|
||
@pytest.fixture() | ||
def db_session(request): | ||
""" | ||
This will hande the db session to tests that declare session in | ||
their arguments | ||
""" | ||
if 'sqla' in request.keywords: | ||
return current_session | ||
else: | ||
raise NotAllowed('This test is not a sqla test') | ||
|
||
|
||
def pytest_sessionstart(): | ||
from py.test import config | ||
|
||
is_sqla = config.getoption('--sqla') | ||
|
||
# Only run database setup on master (in case of xdist/multiproc mode) | ||
if not hasattr(config, 'slaveinput') and is_sqla: | ||
from pyramid.config import Configurator | ||
from .backends.test_sql import BaseModel | ||
setup_sqlalchemy() | ||
engine = _DBSession.bind.engine | ||
print('Creating the tables on the test database %s' % engine) | ||
config = Configurator(settings=settings) | ||
BaseModel.metadata.bind = _DBSession.bind | ||
BaseModel.metadata.drop_all(engine) | ||
BaseModel.metadata.create_all(engine) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[app:main] | ||
use = egg:horus_demo | ||
backend.sqla.url = sqlite:///:memory: |