CORD-1337 test cases for client-side ORM
Change-Id: I7344e54610883bb9f23f98b29ec1cda62270b396
diff --git a/xos/xos_client/xosapi/fake_stub.py b/xos/xos_client/xosapi/fake_stub.py
index dc56178..8cecf18 100644
--- a/xos/xos_client/xosapi/fake_stub.py
+++ b/xos/xos_client/xosapi/fake_stub.py
@@ -5,7 +5,6 @@
import functools
-ContentTypeIdCounter = 0;
ContentTypeMap = {}
class FakeObj(object):
@@ -36,6 +35,10 @@
self.is_set[name] = True
super(FakeObj, self).__setattr__(name, value)
+ @property
+ def self_content_type_id(self):
+ return "xos.%s" % self.__class__.__name__.lower()
+
class FakeExtensionManager(object):
def __init__(self, obj, extensions):
self.obj = obj
@@ -78,8 +81,7 @@
if objName in ContentTypeMap:
ct = ContentTypeMap[objName]
else:
- ct = ContentTypeIdCounter
- ContentTypeIdCount = ContentTypeIdCounter + 1
+ ct = "xos.%s" % objName.lower()
ContentTypeMap[objName] = ct
self.Extensions = FakeExtensionManager(self, {"xos.contentTypeId": ct})
@@ -116,10 +118,41 @@
DESCRIPTOR = FakeDescriptor("Site")
+class Service(FakeObj):
+ FIELDS = ( {"name": "id", "default": 0},
+ {"name": "name", "default": ""}, )
+
+ def __init__(self, **kwargs):
+ return super(Service, self).__init__(self.FIELDS, **kwargs)
+
+ DESCRIPTOR = FakeDescriptor("Service")
+
+class Tag(FakeObj):
+ FIELDS = ( {"name": "id", "default": 0},
+ {"name": "service_id", "default": None},
+ {"name": "name", "default": ""},
+ {"name": "value", "default": ""},
+ {"name": "content_type", "default": None},
+ {"name": "object_id", "default": None},
+ {"name": "slice_ids", "default": 0, "fk_reverse": "Slice"} )
+
+ def __init__(self, **kwargs):
+ return super(Tag, self).__init__(self.FIELDS, **kwargs)
+
+ DESCRIPTOR = FakeDescriptor("Tag")
+
+class ID(FakeObj):
+ pass
+
+class FakeItemList(object):
+ def __init__(self, items):
+ self.items = items
+
class FakeStub(object):
def __init__(self):
+ self.id_counter = 1
self.objs = {}
- for name in ["Slice", "Site"]:
+ for name in ["Slice", "Site", "Tag", "Service"]:
setattr(self, "Get%s" % name, functools.partial(self.get, name))
setattr(self, "List%s" % name, functools.partial(self.list, name))
setattr(self, "Create%s" % name, functools.partial(self.create, name))
@@ -130,35 +163,39 @@
def make_key(self, name, id):
return "%s:%d" % (name, id.id)
- def get(self, classname, id):
+ def get(self, classname, id, metadata=None):
obj = self.objs.get(self.make_key(classname, id), None)
return obj
- def list(self, classname, empty):
- items = None
+ def list(self, classname, empty, metadata=None):
+ items = []
for (k,v) in self.objs.items():
(this_classname, id) = k.split(":")
if this_classname == classname:
items.append(v)
- return items
+ return FakeItemList(items)
- def create(self, classname, obj):
+ def create(self, classname, obj, metadata=None):
+ obj.id = self.id_counter
+ self.id_counter = self.id_counter + 1
k = self.make_key(classname, FakeObj(id=obj.id))
self.objs[k] = obj
+ return obj
- def update(self, classname, obj):
+ def update(self, classname, obj, metadata=None):
# TODO: partial update support?
k = self.make_key(classname, FakeObj(id=obj.id))
self.objs[k] = obj
+ return obj
- def delete(self, classname, id):
+ def delete(self, classname, id, metadata=None):
k = self.make_key(classname, id)
del self.objs[k]
class FakeSymDb(object):
def __init__(self):
self._classes = {}
- for name in ["Slice", "Site"]:
+ for name in ["Slice", "Site", "ID", "Tag", "Service"]:
self._classes["xos.%s" % name] = globals()[name]
diff --git a/xos/xos_client/xosapi/orm.py b/xos/xos_client/xosapi/orm.py
index 35f7a3f..d9f656b 100644
--- a/xos/xos_client/xosapi/orm.py
+++ b/xos/xos_client/xosapi/orm.py
@@ -386,7 +386,7 @@
return self.objects.new(*args, **kwargs)
class ORMStub(object):
- def __init__(self, stub, package_name, invoker=None, caller_kind="grpcapi", sym_db = None, empty = None):
+ def __init__(self, stub, package_name, invoker=None, caller_kind="grpcapi", sym_db = None, empty = None, enable_backoff=True):
self.grpc_stub = stub
self.all_model_names = []
self.all_grpc_classes = {}
@@ -394,6 +394,7 @@
self.reverse_content_type_map = {}
self.invoker = invoker
self.caller_kind = caller_kind
+ self.enable_backoff = enable_backoff
if not sym_db:
from google.protobuf import symbol_database as _symbol_database
@@ -446,9 +447,10 @@
# Hook in place to call Chameleon's invoke method, as soon as we
# have rewritten the synchronizer to use reactor.
return self.invoker.invoke(self.grpc_stub.__class__, name, request, metadata={}).result[0]
- else:
+ elif self.enable_backoff:
# Our own retry mechanism. This works fine if there is a temporary
# failure in connectivity, but does not re-download gRPC schema.
+ import grpc
while True:
backoff = [0.5, 1, 2, 4, 8]
try:
@@ -464,6 +466,10 @@
raise
except:
raise
+ else:
+ method = getattr(self.grpc_stub, name)
+ return method(request, metadata=metadata)
+
def make_ID(self, id):
return self._sym_db._classes["xos.ID"](id=id)
@@ -506,3 +512,4 @@
import convenience.port
import convenience.tag
import convenience.vtrtenant
+
diff --git a/xos/xos_client/xosapi/orm_test.py b/xos/xos_client/xosapi/orm_test.py
index 39d13ad..f276e61 100644
--- a/xos/xos_client/xosapi/orm_test.py
+++ b/xos/xos_client/xosapi/orm_test.py
@@ -16,7 +16,7 @@
def make_coreapi(self):
if USE_FAKE_STUB:
stub = FakeStub()
- api = ORMStub(stub=stub, package_name = "xos", sym_db = FakeSymDb(), empty = FakeObj)
+ api = xosapi.orm.ORMStub(stub=stub, package_name = "xos", sym_db = FakeSymDb(), empty = FakeObj, enable_backoff = False)
return api
else:
return xos_grpc_client.coreapi
@@ -57,11 +57,110 @@
self.assertNotEqual(s, None)
self.assertEqual(s.dumpstr(), '')
+ def test_create(self):
+ orm = self.make_coreapi()
+ site = orm.Site(name="mysite")
+ site.save()
+ self.assertTrue(site.id > 0)
+
+ def test_get(self):
+ orm = self.make_coreapi()
+ site = orm.Site(name="mysite")
+ site.save()
+ self.assertTrue(site.id > 0)
+ got_site = orm.Site.objects.get(id = site.id)
+ self.assertNotEqual(got_site, None)
+ self.assertEqual(got_site.id, site.id)
+
+ def test_delete(self):
+ orm = self.make_coreapi()
+ orig_len_sites = len(orm.Site.objects.all())
+ site = orm.Site(name="mysite")
+ site.save()
+ self.assertTrue(site.id > 0)
+ site.delete()
+ sites = orm.Site.objects.all()
+ self.assertEqual(len(sites), orig_len_sites)
+
+ def test_objects_all(self):
+ orm = self.make_coreapi()
+ orig_len_sites = len(orm.Site.objects.all())
+ site = orm.Site(name="mysite")
+ site.save()
+ sites = orm.Site.objects.all()
+ self.assertEqual(len(sites), orig_len_sites+1)
+
+ def test_objects_first(self):
+ orm = self.make_coreapi()
+ site = orm.Site(name="mysite")
+ site.save()
+ site = orm.Site.objects.first()
+ self.assertNotEqual(site, None)
+
+ def test_content_type_map(self):
+ orm = self.make_coreapi()
+ self.assertTrue( "Slice" in orm.content_type_map.values() )
+ self.assertTrue( "Site" in orm.content_type_map.values() )
+ self.assertTrue( "Tag" in orm.content_type_map.values() )
+
+ def test_foreign_key_get(self):
+ orm = self.make_coreapi()
+ site = orm.Site(name="mysite")
+ site.save()
+ self.assertTrue(site.id > 0)
+ slice = orm.Slice(name="mysite_foo", site_id = site.id)
+ slice.save()
+ self.assertTrue(slice.id > 0)
+ self.assertNotEqual(slice.site, None)
+ self.assertEqual(slice.site.id, site.id)
+
+ def test_foreign_key_set(self):
+ orm = self.make_coreapi()
+ site = orm.Site(name="mysite")
+ site.save()
+ self.assertTrue(site.id > 0)
+ slice = orm.Slice(name="mysite_foo", site = site)
+ slice.save()
+ slice.invalidate_cache()
+ self.assertTrue(slice.id > 0)
+ self.assertNotEqual(slice.site, None)
+ self.assertEqual(slice.site.id, site.id)
+
+ def test_generic_foreign_key_get(self):
+ orm = self.make_coreapi()
+ service = orm.Service(name="myservice")
+ service.save()
+ site = orm.Site(name="mysite")
+ site.save()
+ self.assertTrue(site.id > 0)
+ tag = orm.Tag(service=service, name="mytag", value="somevalue", content_type=site.self_content_type_id, object_id=site.id)
+ tag.save()
+ self.assertTrue(tag.id > 0)
+ self.assertNotEqual(tag.content_object, None)
+ self.assertEqual(tag.content_object.id, site.id)
+
+ def test_generic_foreign_key_set(self):
+ orm = self.make_coreapi()
+ service = orm.Service(name="myservice")
+ service.save()
+ site = orm.Site(name="mysite")
+ site.save()
+ self.assertTrue(site.id > 0)
+ tag = orm.Tag(service=service, name="mytag", value="somevalue")
+ tag.content_object = site
+ tag.invalidate_cache()
+ self.assertEqual(tag.content_type, site.self_content_type_id)
+ self.assertEqual(tag.object_id, site.id)
+ tag.save()
+ self.assertTrue(tag.id > 0)
+ self.assertNotEqual(tag.content_object, None)
+ self.assertEqual(tag.content_object.id, site.id)
+
if USE_FAKE_STUB:
sys.path.append("..")
+ import xosapi.orm
from fake_stub import FakeStub, FakeSymDb, FakeObj
- from orm import ORMStub
print "Using Fake Stub"
@@ -77,6 +176,7 @@
def test_callback():
try:
+ sys.argv = sys.argv[:1] # unittest does not like xos_grpc_client's command line arguments (TODO: find a cooperative approach)
unittest.main()
except exceptions.SystemExit, e:
global exitStatus