Skip to content

Commit

Permalink
Merge branch 'master' into tests
Browse files Browse the repository at this point in the history
  • Loading branch information
tomkukral committed Jan 31, 2018
2 parents 630ac18 + e781bdc commit bc548a0
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 10 deletions.
8 changes: 4 additions & 4 deletions kqueen/models.py
Expand Up @@ -30,12 +30,12 @@
class Cluster(Model, metaclass=ModelMeta):
id = IdField(required=True)
name = StringField(required=True)
provisioner = RelationField()
provisioner = RelationField(remote_class_name='Provisioner')
state = StringField()
kubeconfig = JSONField(encrypted=True)
metadata = JSONField()
created_at = DatetimeField(default=datetime.utcnow)
owner = RelationField(required=True)
owner = RelationField(required=True, remote_class_name='User')

def get_state(self):
try:
Expand Down Expand Up @@ -314,7 +314,7 @@ class Provisioner(Model, metaclass=ModelMeta):
state = StringField(default=config.get('PROVISIONER_UNKNOWN_STATE'))
parameters = JSONField(encrypted=True)
created_at = DatetimeField(default=datetime.utcnow)
owner = RelationField(required=True)
owner = RelationField(required=True, remote_class_name='User')

@classmethod
def list_engines(self):
Expand Down Expand Up @@ -384,7 +384,7 @@ class User(Model, metaclass=ModelMeta):
username = StringField(required=True)
email = StringField(required=False)
password = PasswordField(required=True)
organization = RelationField(required=True)
organization = RelationField(required=True, remote_class_name='Organization')
created_at = DatetimeField(default=datetime.utcnow)
role = StringField(required=True)
active = BoolField(required=True)
Expand Down
29 changes: 24 additions & 5 deletions kqueen/storages/etcd.py
@@ -1,4 +1,5 @@
from .exceptions import BackendError
from .exceptions import FieldError
from Crypto import Random
from Crypto.Cipher import AES
from datetime import datetime
Expand Down Expand Up @@ -286,15 +287,26 @@ class RelationField(Field):
"""Store relations between models.
Serialization format is `ModelName:object_id`.
"""

# TODO: make Model property - limit relation objects only to one model
def __init__(self, *args, **kwargs):
super(RelationField, self).__init__(*args, **kwargs)

self.remote_class_name = kwargs.get('remote_class_name')

def serialize(self):
model_name = self.value.__class__.__name__

if self.remote_class_name and model_name != self.remote_class_name:
msg = "Remote class mismatch, expected: {exp}, got: {got}".format(
exp=self.remote_class_name,
got=model_name
)
raise FieldError(msg)

if self.value and self.__class__.is_field:
return '{model_name}:{object_id}'.format(
model_name=self.value.__class__.__name__,
model_name=model_name,
object_id=self.value.id,
)
else:
Expand All @@ -303,11 +315,18 @@ def serialize(self):
def deserialize(self, serialized, **kwargs):
"""Deserialize relation to real object"""

# TODO: CRITICAL make namespaced and check it
if ':' in serialized:
class_name, object_id = serialized.split(':')

if self.remote_class_name and class_name != self.remote_class_name:
msg = "Remote class mismatch, expected: {exp}, got: {got}".format(
exp=self.remote_class_name,
got=class_name
)
raise FieldError(msg)

obj_class = self._get_related_class(class_name)
# TODO: CRITICAL make namespaced and check it

obj = obj_class.load(kwargs.get('namespace'), object_id)
self.set_value(obj, **kwargs)
Expand Down Expand Up @@ -673,7 +692,7 @@ def __eq__(self, other):
return False

# TODO: implement autogenerated fields (generete them if missing)
# TODO: implement unique field:w
# TODO: implement unique field
# TODO: implement predefined values for fields
# TODO: use validation
# TODO: add is_saved method
Expand Down
4 changes: 4 additions & 0 deletions kqueen/storages/exceptions.py
@@ -1,2 +1,6 @@
class BackendError(Exception):
pass


class FieldError(Exception):
pass
41 changes: 40 additions & 1 deletion kqueen/storages/test_model_fields.py
Expand Up @@ -9,10 +9,11 @@
from kqueen.storages.etcd import RelationField
from kqueen.storages.etcd import StringField
from kqueen.storages.exceptions import BackendError
from kqueen.storages.exceptions import FieldError

import datetime
import pytest
import itertools
import pytest


def create_model(required=False, global_ns=False, encrypted=False):
Expand Down Expand Up @@ -327,6 +328,44 @@ def fake_related_class(their, class_name):
assert hasattr(loaded, 'relation')
assert loaded.relation == self.obj2

def test_deserialization_full(self, monkeypatch):
def fake_related_class(their, class_name):
return self.obj1.__class__

monkeypatch.setattr(RelationField, '_get_related_class', fake_related_class)

serialized = '{cls}:{id}'.format(
cls=self.obj2.__class__,
id=self.obj2.id,
)

self.obj1._relation.deserialize(serialized, namespace=namespace)

assert self.obj2.get_dict(True) == self.obj1.relation.get_dict(True)


class TestRelationRemoteMismatch:
@pytest.fixture(autouse=True)
def prepare(self, monkeypatch):
self.field = RelationField(remote_class_name="RemoteClass")
self.field.value = "MyClass:27ef44b5-0776-4e08-93d4-074717e7e965"

def fake_related_class(their, class_name):
class TestObj:
pass

return TestObj

monkeypatch.setattr(RelationField, '_get_related_class', fake_related_class)

def test_serialize_raises(self):
with pytest.raises(FieldError):
self.field.serialize()

def test_deserialize_raises(self):
with pytest.raises(FieldError):
self.field.deserialize(self.field.value)


class TestNamespaces:
def setup(self):
Expand Down

0 comments on commit bc548a0

Please sign in to comment.