CORD-1169 implement __str__ and __repr__ for orm

Change-Id: Ifccf7221f53af33fb62ed162e92c56121a1e17fc
diff --git a/xos/tools/xossh b/xos/tools/xossh
index fa61ebe..2f26641 100755
--- a/xos/tools/xossh
+++ b/xos/tools/xossh
@@ -1,5 +1,7 @@
 #!/bin/bash
 
-# This is a stub for launching xossh in the xosproject/xos-client container
+# This is a stub for launching xossh in the xosproject/xos-client container.
+# It's assumed that this script is being invoked on the head node. 
 
-docker run --rm -it -v /opt/cord_profile/im_cert_chain.pem:/usr/local/share/ca-certificates/local_certs.crt xosproject/xos-client:candidate -u xosadmin@opencord.org -p `cat /opt/cord/build/platform-install/credentials/xosadmin@opencord.org`
\ No newline at end of file
+docker pull docker-registry:5000/xosproject/xos-client:candidate
+docker run --rm -it -v /opt/cord_profile/im_cert_chain.pem:/usr/local/share/ca-certificates/local_certs.crt docker-registry:5000/xosproject/xos-client:candidate -u xosadmin@opencord.org -p `cat /opt/cord/build/platform-install/credentials/xosadmin@opencord.org`
\ No newline at end of file
diff --git a/xos/xos_client/README.md b/xos/xos_client/README.md
new file mode 100644
index 0000000..1d45a2c
--- /dev/null
+++ b/xos/xos_client/README.md
@@ -0,0 +1,19 @@
+# xos_client #
+
+Xos\_client is a python library that is used by synchronizers and other components that need to communicate with the xos core. It includes a self-learning gRPC client (based on Chameleon) as well as a client-side ORM layer. 
+
+Xos\_client includes a python setup.py program that may be used to install the library. As part of the standard CORD build, the container image xosproject/xos-client is created with xos_client already installed, so that it may easily be used as a base image for other components.  
+
+## xossh ##
+
+Xossh is a shell for interactively using the xos client API and client ORM layer. Generally xossh is run inside a container, and the xos\_client container is configured to run xossh as its default entrypoint. A script is provided in xos/tools to assist in invoking xossh from inside the head node environment. 
+
+## Running Unit Tests ##
+
+Some unit tests (orm\_test.py) require an environment where the xos\_client library is installed, and a core API container is available to serve the API. It's suggested that the xos-client container be used together with a frontend or CiaB installation. For example,
+
+    docker run --rm -it --entrypoint bash docker-registry:5000/xosproject/xos-client:candidate
+
+Once inside of the container, run the test(s). For example,
+
+    python ./usr/local/lib/python2.7/dist-packages/xosapi/orm_test.py
diff --git a/xos/xos_client/xosapi/orm.py b/xos/xos_client/xosapi/orm.py
index 12e658f..c4e1a3e 100644
--- a/xos/xos_client/xosapi/orm.py
+++ b/xos/xos_client/xosapi/orm.py
@@ -164,8 +164,29 @@
             setattr(self._wrapped_class, name, value)
 
     def __repr__(self):
+        class_name = self._wrapped_class.__class__.__name__
+        id = getattr(self._wrapped_class, "id", "noid")
+        name = getattr(self._wrapped_class, "name", None)
+        if name:
+            return "<%s: %s>" % (class_name, name)
+        else:
+            return "<%s: id-%s>" % (class_name, id)
+
+    def __str__(self):
+        class_name = self._wrapped_class.__class__.__name__
+        id = getattr(self._wrapped_class, "id", "noid")
+        name = getattr(self._wrapped_class, "name", None)
+        if name:
+            return name
+        else:
+            return "%s-%s" % (class_name, id)
+
+    def dumpstr(self):
         return self._wrapped_class.__repr__()
 
+    def dump(self):
+        print self.dumpstr()
+
     def invalidate_cache(self, name=None):
         if name:
             if name in self.cache:
diff --git a/xos/xos_client/xosapi/orm_test.py b/xos/xos_client/xosapi/orm_test.py
new file mode 100644
index 0000000..ed44435
--- /dev/null
+++ b/xos/xos_client/xosapi/orm_test.py
@@ -0,0 +1,54 @@
+import exceptions
+import shutil
+import sys
+import unittest
+
+from twisted.internet import reactor
+from xosapi import xos_grpc_client
+
+exitStatus = -1
+
+# TODO: See if there's a way to stub this out using a fake xos_grpc_client
+# instead of the real one.
+
+class TestORM(unittest.TestCase):
+    def test_repr_name(self):
+        s = xos_grpc_client.coreapi.Slice(name="foo")
+        self.assertNotEqual(s, None)
+        self.assertEqual(repr(s), "<Slice: foo>")
+
+    def test_str_name(self):
+        s = xos_grpc_client.coreapi.Slice(name="foo")
+        self.assertNotEqual(s, None)
+        self.assertEqual(str(s), "foo")
+
+    def test_dumpstr_name(self):
+        s = xos_grpc_client.coreapi.Slice(name="foo")
+        self.assertNotEqual(s, None)
+        self.assertEqual(s.dumpstr(), 'name: "foo"\n')
+
+    def test_repr_noname(self):
+        s = xos_grpc_client.coreapi.Slice()
+        self.assertNotEqual(s, None)
+        self.assertEqual(repr(s), "<Slice: id-0>")
+
+    def test_str_noname(self):
+        s = xos_grpc_client.coreapi.Slice()
+        self.assertNotEqual(s, None)
+        self.assertEqual(str(s), "Slice-0")
+
+    def test_dumpstr_noname(self):
+        s = xos_grpc_client.coreapi.Slice()
+        self.assertNotEqual(s, None)
+        self.assertEqual(s.dumpstr(), '')
+
+def test_callback():
+    try:
+        unittest.main()
+    except exceptions.SystemExit, e:
+        global exitStatus
+        exitStatus = e.code
+
+xos_grpc_client.start_api_parseargs(test_callback)
+
+sys.exit(exitStatus)
diff --git a/xos/xos_client/xossh b/xos/xos_client/xossh
index 8a480d3..600211f 100644
--- a/xos/xos_client/xossh
+++ b/xos/xos_client/xossh
@@ -118,7 +118,8 @@
     print 'listModelDefs()'
 
 def examples():
-    print 'coreapi.Slice.objects.all() # list all slices'
+    print 'Slice.objects.all() # list all slices'
+    print 'Slice.objects.first().dump() # dump the first slice'
     print 's = Slice.objects.new() # create a new slice'
     print 's.name = "mysite_foo" # set a slice name'
     print 's.site_id = coreapi.Site.objects.all()[0].id # grab the first site'