Newer
Older
from enum import Enum
from common.orm.Exceptions import ConstraintException
from common.orm.Database import Database
from common.orm.Factory import get_database_backend
from common.orm.backend.BackendEnum import BackendEnum
from common.orm.backend._Backend import _Backend
from common.orm.fields.BooleanField import BooleanField
from common.orm.fields.EnumeratedField import EnumeratedField
from common.orm.fields.FloatField import FloatField
from common.orm.fields.ForeignKeyField import ForeignKeyField
from common.orm.fields.IntegerField import IntegerField
from common.orm.fields.PrimaryKeyField import PrimaryKeyField
from common.orm.fields.StringField import StringField
from common.orm.model.Model import DEFAULT_PRIMARY_KEY_NAME, Model
LOGGER = logging.getLogger(__name__)
def test_database_instantiation():
with pytest.raises(AttributeError) as e:
str_class_path = '{}.{}'.format(_Backend.__module__, _Backend.__name__)
assert str(e.value) == 'backend must inherit from {}'.format(str_class_path)
assert Database(get_database_backend(BackendEnum.INMEMORY)) is not None
def test_model_without_attributes():
with pytest.raises(AttributeError) as e:
Model(None, 'valid-uuid')
str_class_path = '{}.{}'.format(Database.__module__, Database.__name__)
assert str(e.value) == 'database must inherit from {}'.format(str_class_path)
database = Database(get_database_backend(BackendEnum.INMEMORY))
with pytest.raises(ValueError) as e:
msg = '{:s}() is out of range: allow_empty(False).'
assert str(e.value) == msg.format(DEFAULT_PRIMARY_KEY_NAME)
with pytest.raises(TypeError) as e:
Model(database, 23)
msg = '{:s}(23) is of a wrong type(int). Accepted type_or_types(<class \'str\'>).'
assert str(e.value) == msg.format(DEFAULT_PRIMARY_KEY_NAME)
with pytest.raises(TypeError) as e:
Model(database, 23.5)
msg = '{:s}(23.5) is of a wrong type(float). Accepted type_or_types(<class \'str\'>).'
assert str(e.value) == msg.format(DEFAULT_PRIMARY_KEY_NAME)
with pytest.raises(TypeError) as e:
Model(database, True)
msg = '{:s}(True) is of a wrong type(bool). Accepted type_or_types(<class \'str\'>).'
assert str(e.value) == msg.format(DEFAULT_PRIMARY_KEY_NAME)
with pytest.raises(TypeError) as e:
Model(database, ['a'])
msg = '{:s}([\'a\']) is of a wrong type(list). Accepted type_or_types(<class \'str\'>).'
assert str(e.value) == msg.format(DEFAULT_PRIMARY_KEY_NAME)
Model(database, 'valid-primary-key')
database = Database(get_database_backend(BackendEnum.INMEMORY))
with pytest.raises(AttributeError) as e:
class WrongTestModel(Model): # pylint: disable=unused-variable
pk = PrimaryKeyField()
name = StringField(min_length=1)
age = IntegerField(min_value=0)
salary = FloatField(min_value=0.0)
active = BooleanField()
pk2 = PrimaryKeyField()
assert str(e.value) == 'PrimaryKeyField for Model(WrongTestModel) already set to attribute(pk)'
class GenderEnum(Enum):
FEMALE = 'female'
MALE = 'male'
class TestModel(Model):
pk = PrimaryKeyField()
name = StringField(min_length=1)
age = IntegerField(min_value=0)
salary = FloatField(min_value=0.0)
active = BooleanField()
gender = EnumeratedField(GenderEnum)
TestModel(database, None)
assert str(e.value) == 'pk(None) is required. It cannot be None.'
with pytest.raises(ValueError) as e:
TestModel(database, '')
assert str(e.value) == 'pk() is out of range: allow_empty(False).'
obj = TestModel(database, 'valid-pk')
assert obj is not None
with pytest.raises(ValueError) as e:
obj.pk = 'another-valid-pk'
assert str(e.value) == 'PrimaryKeyField cannot be modified'
def test_model_with_primarykey_and_attributes():
database = Database(get_database_backend(BackendEnum.INMEMORY))
class GenderEnum(Enum):
FEMALE = 'female'
MALE = 'male'
with pytest.raises(AttributeError) as e:
class BadTestModel(Model):
pk_auto = StringField() # field using default name of primary key
name = StringField(min_length=5, max_length=10)
age = IntegerField(min_value=0)
salary = FloatField(min_value=0.0)
active = BooleanField()
gender = EnumeratedField(GenderEnum)
msg = 'PrimaryKeyField for Model(BadTestModel) not defined and attribute "pk_auto" already used. '\
'Leave attribute name "pk_auto" for automatic PrimaryKeyField, or set a PrimaryKeyField.'
assert str(e.value) == msg
class TestModel(Model):
pk = PrimaryKeyField()
name = StringField(min_length=5, max_length=10)
age = IntegerField(min_value=0)
salary = FloatField(min_value=0.0)
active = BooleanField()
gender = EnumeratedField(GenderEnum)
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
obj = TestModel(database, 'valid-pk')
assert obj is not None
with pytest.raises(AttributeError) as e:
del obj.name
assert str(e.value) == 'Attribute "name" cannot be deleted'
with pytest.raises(TypeError) as e:
obj.name = 55
assert str(e.value) == "name(55) is of a wrong type(int). Accepted type_or_types(<class 'str'>)."
with pytest.raises(TypeError) as e:
obj.name = 55.5
assert str(e.value) == "name(55.5) is of a wrong type(float). Accepted type_or_types(<class 'str'>)."
with pytest.raises(TypeError) as e:
obj.name = True
assert str(e.value) == "name(True) is of a wrong type(bool). Accepted type_or_types(<class 'str'>)."
with pytest.raises(TypeError) as e:
obj.age = 'too old'
assert str(e.value) == "age(too old) is of a wrong type(str). Accepted type_or_types(<class 'int'>)."
with pytest.raises(TypeError) as e:
obj.age = 37.5
assert str(e.value) == "age(37.5) is of a wrong type(float). Accepted type_or_types(<class 'int'>)."
with pytest.raises(TypeError) as e:
obj.salary = 'too high'
msg = "salary(too high) is of a wrong type(str). Accepted type_or_types((<class 'int'>, <class 'float'>))."
assert str(e.value) == msg
with pytest.raises(TypeError) as e:
obj.active = 'active'
assert str(e.value) == "active(active) is of a wrong type(str). Accepted type_or_types(<class 'bool'>)."
with pytest.raises(TypeError) as e:
obj.active = 27
assert str(e.value) == "active(27) is of a wrong type(int). Accepted type_or_types(<class 'bool'>)."
with pytest.raises(TypeError) as e:
obj.active = 92.5
assert str(e.value) == "active(92.5) is of a wrong type(float). Accepted type_or_types(<class 'bool'>)."
with pytest.raises(ValueError) as e:
obj.name = ''
assert str(e.value) == 'name() is out of range: allow_empty(False).'
with pytest.raises(ValueError) as e:
obj.name = 'John'
assert str(e.value) == 'name(John) is out of range: min_length(5).'
with pytest.raises(ValueError) as e:
obj.name = 'John Smith Willson'
assert str(e.value) == 'name(John Smith Willson) is out of range: max_value(10).'
with pytest.raises(TypeError) as e:
obj.gender = 51
assert str(e.value) == "gender(51) is of a wrong type(int). Accepted type_or_types(<enum 'GenderEnum'>)."
with pytest.raises(TypeError) as e:
obj.gender = 55.5
assert str(e.value) == "gender(55.5) is of a wrong type(float). Accepted type_or_types(<enum 'GenderEnum'>)."
with pytest.raises(TypeError) as e:
obj.gender = False
assert str(e.value) == "gender(False) is of a wrong type(bool). Accepted type_or_types(<enum 'GenderEnum'>)."
with pytest.raises(TypeError) as e:
obj.gender = 'male'
assert str(e.value) == "gender(male) is of a wrong type(str). Accepted type_or_types(<enum 'GenderEnum'>)."
obj.name = 'John Smith'
obj.age = 37
obj.salary = 5023.52
obj.active = True
obj.gender = GenderEnum.MALE
assert repr(obj) == "TestModel(pk='valid-pk'(PK), name='John Smith', age=37, salary=5023.52, active=True, "\
"gender=<GenderEnum.MALE: 'male'>)"
database = Database(get_database_backend(BackendEnum.INMEMORY))
class GenderEnum(Enum):
FEMALE = 'female'
MALE = 'male'
class TestModel(Model):
pk = PrimaryKeyField()
name = StringField(min_length=5, max_length=10)
age = IntegerField(min_value=0, required=True)
salary = FloatField(min_value=0.0)
active = BooleanField()
gender = EnumeratedField(GenderEnum)
obj = TestModel(database, 'valid-pk')
assert obj is not None
obj.name = 'John Smith'
obj.salary = 5023.52
obj.active = True
assert repr(obj) == "TestModel(pk='valid-pk'(PK), name='John Smith', age=None, salary=5023.52, active=True, "\
"gender=None)"
with pytest.raises(ValueError) as e:
obj.save()
assert str(e.value) == 'age(None) is required. It cannot be None.'
obj.age = 37
assert repr(obj) == "TestModel(pk='valid-pk'(PK), name='John Smith', age=37, salary=5023.52, active=True, "\
"gender=None)"
with pytest.raises(ValueError) as e:
obj.save()
assert str(e.value) == 'gender(None) is required. It cannot be None.'
obj.gender = GenderEnum.MALE
db_entries = database.dump()
assert len(db_entries) == 1
assert db_entries[0] == (
'dict', 'TestModel[valid-pk]',
"{'active': 'True', 'age': '37', 'gender': 'MALE', 'name': 'John Smith', 'pk': 'valid-pk', "\
"'salary': '5023.52'}")
obj2 = TestModel(database, 'valid-pk', auto_load=False)
assert repr(obj2) == "TestModel(pk='valid-pk'(PK), name=None, age=None, salary=None, active=None, gender=None)"
assert repr(obj2) == "TestModel(pk='valid-pk'(PK), name='John Smith', age=37, salary=5023.52, active=True, "\
"gender=<GenderEnum.MALE: 'male'>)"
obj2 = TestModel(database, 'valid-pk', auto_load=True)
assert obj2 is not None
assert repr(obj2) == "TestModel(pk='valid-pk'(PK), name='John Smith', age=37, salary=5023.52, active=True, "\
"gender=<GenderEnum.MALE: 'male'>)"
obj2.delete()
assert len(database.dump()) == 0
obj2.save()
assert len(database.dump()) == 1
database.clear_all()
assert len(database.dump()) == 0
database = Database(get_database_backend(BackendEnum.INMEMORY))
class GenderEnum(Enum):
FEMALE = 'female'
MALE = 'male'
class Team(Model):
pk = PrimaryKeyField()
name = StringField(max_length=10, required=True)
class Workplace(Model):
pk = PrimaryKeyField()
name = StringField(max_length=10, required=True)
class Member(Model):
pk = PrimaryKeyField()
team = ForeignKeyField(Team)
place = ForeignKeyField(Workplace, required=False)
name = StringField(max_length=10, required=True)
gender = EnumeratedField(GenderEnum)
team_dev_ops = Team(database, 'dev-ops')
team_dev_ops.name = 'Dev Ops'
assert team_dev_ops is not None
assert repr(team_dev_ops) == "Team(pk='dev-ops'(PK), name='Dev Ops')"
workplace_bcn = Workplace(database, 'bcn')
workplace_bcn.name = 'Barcelona'
assert workplace_bcn is not None
assert repr(workplace_bcn) == "Workplace(pk='bcn'(PK), name='Barcelona')"
member_john = Member(database, 'john')
member_john.team = team_dev_ops
member_john.place = workplace_bcn
assert member_john is not None
assert repr(member_john) == "Member(pk='john'(PK), team='Team[dev-ops]', place='Workplace[bcn]', name='John', "\
"gender=None)"
with pytest.raises(ValueError) as e:
member_john.save()
assert str(e.value) == 'gender(None) is required. It cannot be None.'
member_john.gender = GenderEnum.MALE
with pytest.raises(ConstraintException) as e:
assert str(e.value) == 'Required Keys (Team[dev-ops], Workplace[bcn]) does not exist'
assert repr(Workplace(database, workplace_bcn.pk)) == "Workplace(pk='bcn'(PK), name='Barcelona')"
with pytest.raises(ConstraintException) as e:
assert str(e.value) == 'Required Keys (Team[dev-ops]) does not exist'
assert repr(Team(database, team_dev_ops.pk)) == "Team(pk='dev-ops'(PK), name='Dev Ops')"
assert repr(Member(database, member_john.pk)) == \
"Member(pk='john'(PK), team='Team[dev-ops]', place='Workplace[bcn]', name='John', "\
"gender=<GenderEnum.MALE: 'male'>)"
with pytest.raises(ConstraintException) as e:
workplace_bcn.delete()
assert str(e.value) == 'Instance is used by Keys (Member[john]:place)'
with pytest.raises(ConstraintException) as e:
team_dev_ops.delete()
assert str(e.value) == 'Instance is used by Keys (Member[john]:team)'
workplace_mad = Workplace(database, 'mad')
workplace_mad.name = 'Madrid'
assert workplace_mad is not None
assert repr(workplace_mad) == "Workplace(pk='mad'(PK), name='Madrid')"
member_john = Member(database, 'john')
member_john.name = 'John'
member_john.place = workplace_mad
assert member_john is not None
assert repr(member_john) == \
"Member(pk='john'(PK), team='Team[dev-ops]', place='Workplace[mad]', name='John', "\
"gender=<GenderEnum.MALE: 'male'>)"
with pytest.raises(ConstraintException) as e:
member_john.save()
assert str(e.value) == 'Required Keys (Workplace[mad]) does not exist'
workplace_mad.save()
assert repr(Workplace(database, workplace_mad.pk)) == "Workplace(pk='mad'(PK), name='Madrid')"
member_john.save()
member_john = Member(database, 'john')
with pytest.raises(ValueError) as e:
del member_john.place
del member_john.team
assert str(e.value) == 'team(None) is required. It cannot be None.'
member_jane = Member(database, 'jane')
member_jane.name = 'Jane'
member_jane.place = workplace_mad
assert member_jane is not None
assert repr(member_jane) == "Member(pk='jane'(PK), team=None, place='Workplace[mad]', name='Jane', gender=None)"
with pytest.raises(ValueError) as e:
member_jane.save()
assert str(e.value) == 'team(None) is required. It cannot be None.'
member_jane.team = team_dev_ops
with pytest.raises(ValueError) as e:
member_jane.save()
assert str(e.value) == 'gender(None) is required. It cannot be None.'
member_jane.gender = GenderEnum.FEMALE
member_jane.save()
assert repr(Member(database, member_jane.pk)) == \
"Member(pk='jane'(PK), team='Team[dev-ops]', place='Workplace[mad]', name='Jane', "\
"gender=<GenderEnum.FEMALE: 'female'>)"
member_brad = Member(database, 'brad')
assert member_brad is not None
assert repr(member_brad) == "Member(pk='brad'(PK), team=None, place=None, name=None, gender=None)"
with pytest.raises(ValueError) as e:
assert str(e.value) == 'team(None) is required. It cannot be None.'
member_brad.team = team_dev_ops
with pytest.raises(ValueError) as e:
member_brad.save()
assert str(e.value) == 'name(None) is required. It cannot be None.'
member_brad.name = 'Brad'
assert repr(member_brad) == "Member(pk='brad'(PK), team=\'Team[dev-ops]\', place=None, name='Brad', gender=None)"
with pytest.raises(ValueError) as e:
member_brad.save()
assert str(e.value) == 'gender(None) is required. It cannot be None.'
member_brad.gender = GenderEnum.MALE
assert repr(Member(database, member_brad.pk)) == \
"Member(pk='brad'(PK), team='Team[dev-ops]', place=None, name='Brad', gender=<GenderEnum.MALE: 'male'>)"
team_admin = Team(database, 'admin')
team_admin.name = 'Admin'
team_admin.save()
assert repr(Team(database, team_admin.pk)) == "Team(pk='admin'(PK), name='Admin')"
member_brad = Member(database, member_brad.pk)
assert repr(member_brad) == \
"Member(pk='brad'(PK), team='Team[dev-ops]', place=None, name='Brad', gender=<GenderEnum.MALE: 'male'>)"
assert repr(member_brad) == \
"Member(pk='brad'(PK), team='Team[admin]', place=None, name='Brad', gender=<GenderEnum.MALE: 'male'>)"
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
assert repr(Member(database, member_brad.pk)) == \
"Member(pk='brad'(PK), team='Team[admin]', place=None, name='Brad', gender=<GenderEnum.MALE: 'male'>)"
references = sorted(team_dev_ops.references())
assert len(references) == 2
assert references[0] == ('Member[jane]', 'team')
assert references[1] == ('Member[john]', 'team')
references = sorted(workplace_bcn.references())
assert len(references) == 0
references = sorted(workplace_mad.references())
assert len(references) == 2
assert references[0] == ('Member[jane]', 'place')
assert references[1] == ('Member[john]', 'place')
db_entries = database.dump()
LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries)))
for db_entry in db_entries:
LOGGER.info(' [{:>4s}] {:40s} :: {:s}'.format(*db_entry))
LOGGER.info('-----------------------------------------------------------')
assert len(db_entries) == 10
assert db_entries[0] == ('dict', "Member[brad]",
"{'gender': 'MALE', 'name': 'Brad', 'pk': 'brad', 'team': 'Team[admin]'}")
assert db_entries[1] == ('dict', "Member[jane]",
"{'gender': 'FEMALE', 'name': 'Jane', 'pk': 'jane', 'place': 'Workplace[mad]', "\
"'team': 'Team[dev-ops]'}")
assert db_entries[2] == ('dict', "Member[john]",
"{'gender': 'MALE', 'name': 'John', 'pk': 'john', 'place': 'Workplace[mad]', "\
"'team': 'Team[dev-ops]'}")
assert db_entries[3] == ('dict', "Team[admin]",
"{'name': 'Admin', 'pk': 'admin'}")
assert db_entries[4] == ('set' , "Team[admin]/references",
"{'Member[brad]:team'}")
assert db_entries[5] == ('dict', "Team[dev-ops]",
"{'name': 'Dev Ops', 'pk': 'dev-ops'}")
assert db_entries[6] == ('set' , "Team[dev-ops]/references",
"{'Member[jane]:team', 'Member[john]:team'}")
assert db_entries[7] == ('dict', "Workplace[bcn]",
"{'name': 'Barcelona', 'pk': 'bcn'}")
assert db_entries[8] == ('dict', "Workplace[mad]",
"{'name': 'Madrid', 'pk': 'mad'}")
assert db_entries[9] == ('set' , "Workplace[mad]/references",
"{'Member[jane]:place', 'Member[john]:place'}")
Member(database, member_john.pk).delete()
db_entries = database.dump()
LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries)))
for db_entry in db_entries:
LOGGER.info(' [{:>4s}] {:40s} :: {:s}'.format(*db_entry))
LOGGER.info('-----------------------------------------------------------')
assert len(db_entries) == 9
assert db_entries[ 0] == ('dict', 'Member[brad]',
"{'gender': 'MALE', 'name': 'Brad', 'pk': 'brad', 'team': 'Team[admin]'}")
assert db_entries[ 1] == ('dict', 'Member[jane]',
"{'gender': 'FEMALE', 'name': 'Jane', 'pk': 'jane', 'place': 'Workplace[mad]', "\
"'team': 'Team[dev-ops]'}")
assert db_entries[ 2] == ('dict', 'Team[admin]',
"{'name': 'Admin', 'pk': 'admin'}")
assert db_entries[ 3] == ('set', 'Team[admin]/references',
"{'Member[brad]:team'}")
assert db_entries[ 4] == ('dict', 'Team[dev-ops]',
"{'name': 'Dev Ops', 'pk': 'dev-ops'}")
assert db_entries[ 5] == ('set', 'Team[dev-ops]/references',
"{'Member[jane]:team'}")
assert db_entries[ 6] == ('dict', 'Workplace[bcn]',
"{'name': 'Barcelona', 'pk': 'bcn'}")
assert db_entries[ 7] == ('dict', 'Workplace[mad]',
"{'name': 'Madrid', 'pk': 'mad'}")
assert db_entries[ 8] == ('set', 'Workplace[mad]/references',
"{'Member[jane]:place'}")