CORD-1939: support for nose2
modify test cases to be compliant with automation
Cherry-pick from cord-4.1 b641f9060eb912470a284bfd04dd955b031af708

Change-Id: I01914ccfb57979994534c6128bc5ff72ae10f64b
diff --git a/docs/dev/unittest.md b/docs/dev/unittest.md
new file mode 100644
index 0000000..fd667ae
--- /dev/null
+++ b/docs/dev/unittest.md
@@ -0,0 +1,27 @@
+# Unit Testing
+
+XOS supports automated unit tests using the `nose2` unit testing framework. 
+
+## Setting up a unit testing environment
+
+To run unit tests, an environment needs to be setup with the appropriate python libraries used by the unit testing framework and by the XOS libraries that are being tested. One way to accomplish this is to setup a [virtual-env](dev/local_env.md). You will also need to copy Chameleon from `component/chameleon` to `containers/xos/tmp.chameleon`. Here is a set of commands that may prove useful:
+
+```brew install graphviz
+pip install --install-option="--include-path=/usr/local/include/" --install-option="--library-path=/usr/local/lib/" pygraphviz
+source scripts/setup_venv.sh
+pip install nose2 mock
+cp -R ../../component/chameleon containers/xos/tmp.chameleon```
+
+## Running unit tests
+
+To run unit tests, go to the root of the xos repository and run the following:
+
+```nose2 --verbose --exclude-ignored-files```
+
+## Writing new unit tests
+
+New test filename should start with the string `test`. For example, `test_mymodule.py`. If named properly, then `nose2` will automatically pick them up. 
+
+## Ignoring unwanted unit tests
+
+Some tests are still being migrated to the unit testing framework and/or require features that may not be present in the virtual-env. Placing the string `# TEST_FRAMEWORK: IGNORE` anywhere in a python file will prevent it from being executed automatically by the test framework. 
\ No newline at end of file
diff --git a/lib/__init__.py b/lib/__init__.py
new file mode 100644
index 0000000..42722a8
--- /dev/null
+++ b/lib/__init__.py
@@ -0,0 +1,14 @@
+
+# Copyright 2017-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/lib/xos-config/tests/config_test.py b/lib/xos-config/tests/test_config.py
similarity index 98%
rename from lib/xos-config/tests/config_test.py
rename to lib/xos-config/tests/test_config.py
index 1ce1ce6..bc9ad13 100644
--- a/lib/xos-config/tests/config_test.py
+++ b/lib/xos-config/tests/test_config.py
@@ -52,6 +52,10 @@
     Testing the XOS Config Module
     """
 
+    def setUp(self):
+        # In case some other testcase in nose has left config in an unclean state
+        Config.clear()
+
     def tearDown(self):
         # NOTE clear the config after each test
         Config.clear()
@@ -239,4 +243,4 @@
 
 
 if __name__ == '__main__':
-    unittest.main()
\ No newline at end of file
+    unittest.main()
diff --git a/lib/xos-config/xosconfig/__init__.py b/lib/xos-config/xosconfig/__init__.py
index b7ad3d8..105d4a0 100644
--- a/lib/xos-config/xosconfig/__init__.py
+++ b/lib/xos-config/xosconfig/__init__.py
@@ -14,4 +14,4 @@
 # limitations under the License.
 
 
-from .config import Config
\ No newline at end of file
+from .config import Config
diff --git a/lib/xos-genx/tests/__init__.py b/lib/xos-genx/xos-genx-tests/__init__.py
similarity index 100%
rename from lib/xos-genx/tests/__init__.py
rename to lib/xos-genx/xos-genx-tests/__init__.py
diff --git a/lib/xos-genx/tests/attics/xosmodel_bottom.py b/lib/xos-genx/xos-genx-tests/attics/xosmodel_bottom.py
similarity index 100%
rename from lib/xos-genx/tests/attics/xosmodel_bottom.py
rename to lib/xos-genx/xos-genx-tests/attics/xosmodel_bottom.py
diff --git a/lib/xos-genx/tests/attics/xosmodel_header.py b/lib/xos-genx/xos-genx-tests/attics/xosmodel_header.py
similarity index 100%
rename from lib/xos-genx/tests/attics/xosmodel_header.py
rename to lib/xos-genx/xos-genx-tests/attics/xosmodel_header.py
diff --git a/lib/xos-genx/tests/attics/xosmodel_model.py b/lib/xos-genx/xos-genx-tests/attics/xosmodel_model.py
similarity index 100%
rename from lib/xos-genx/tests/attics/xosmodel_model.py
rename to lib/xos-genx/xos-genx-tests/attics/xosmodel_model.py
diff --git a/lib/xos-genx/tests/attics/xosmodel_top.py b/lib/xos-genx/xos-genx-tests/attics/xosmodel_top.py
similarity index 100%
rename from lib/xos-genx/tests/attics/xosmodel_top.py
rename to lib/xos-genx/xos-genx-tests/attics/xosmodel_top.py
diff --git a/lib/xos-genx/tests/counts b/lib/xos-genx/xos-genx-tests/counts
similarity index 100%
rename from lib/xos-genx/tests/counts
rename to lib/xos-genx/xos-genx-tests/counts
diff --git a/lib/xos-genx/tests/django_generator_test.py b/lib/xos-genx/xos-genx-tests/django_generator_test.py
similarity index 100%
rename from lib/xos-genx/tests/django_generator_test.py
rename to lib/xos-genx/xos-genx-tests/django_generator_test.py
diff --git a/lib/xos-genx/tests/field_graph_test.py b/lib/xos-genx/xos-genx-tests/field_graph_test.py
similarity index 100%
rename from lib/xos-genx/tests/field_graph_test.py
rename to lib/xos-genx/xos-genx-tests/field_graph_test.py
diff --git a/lib/xos-genx/tests/general_security_test.py b/lib/xos-genx/xos-genx-tests/general_security_test.py
similarity index 100%
rename from lib/xos-genx/tests/general_security_test.py
rename to lib/xos-genx/xos-genx-tests/general_security_test.py
diff --git a/lib/xos-genx/tests/general_validation_test.py b/lib/xos-genx/xos-genx-tests/general_validation_test.py
similarity index 100%
rename from lib/xos-genx/tests/general_validation_test.py
rename to lib/xos-genx/xos-genx-tests/general_validation_test.py
diff --git a/lib/xos-genx/tests/graph_test.py b/lib/xos-genx/xos-genx-tests/graph_test.py
similarity index 100%
rename from lib/xos-genx/tests/graph_test.py
rename to lib/xos-genx/xos-genx-tests/graph_test.py
diff --git a/lib/xos-genx/tests/helpers.py b/lib/xos-genx/xos-genx-tests/helpers.py
similarity index 100%
rename from lib/xos-genx/tests/helpers.py
rename to lib/xos-genx/xos-genx-tests/helpers.py
diff --git a/lib/xos-genx/tests/optimize_test.py b/lib/xos-genx/xos-genx-tests/optimize_test.py
similarity index 100%
rename from lib/xos-genx/tests/optimize_test.py
rename to lib/xos-genx/xos-genx-tests/optimize_test.py
diff --git a/lib/xos-genx/tests/out/.gitignore b/lib/xos-genx/xos-genx-tests/out/.gitignore
similarity index 100%
rename from lib/xos-genx/tests/out/.gitignore
rename to lib/xos-genx/xos-genx-tests/out/.gitignore
diff --git a/lib/xos-genx/tests/package_test.py b/lib/xos-genx/xos-genx-tests/package_test.py
similarity index 100%
rename from lib/xos-genx/tests/package_test.py
rename to lib/xos-genx/xos-genx-tests/package_test.py
diff --git a/lib/xos-genx/tests/parse_test.py b/lib/xos-genx/xos-genx-tests/parse_test.py
similarity index 100%
rename from lib/xos-genx/tests/parse_test.py
rename to lib/xos-genx/xos-genx-tests/parse_test.py
diff --git a/lib/xos-genx/tests/policy_test.py b/lib/xos-genx/xos-genx-tests/policy_test.py
similarity index 100%
rename from lib/xos-genx/tests/policy_test.py
rename to lib/xos-genx/xos-genx-tests/policy_test.py
diff --git a/lib/xos-genx/tests/pure_proto_test.py b/lib/xos-genx/xos-genx-tests/pure_proto_test.py
similarity index 100%
rename from lib/xos-genx/tests/pure_proto_test.py
rename to lib/xos-genx/xos-genx-tests/pure_proto_test.py
diff --git a/lib/xos-genx/tests/rlinks_test.py b/lib/xos-genx/xos-genx-tests/rlinks_test.py
similarity index 100%
rename from lib/xos-genx/tests/rlinks_test.py
rename to lib/xos-genx/xos-genx-tests/rlinks_test.py
diff --git a/lib/xos-genx/tests/swagger_test.py b/lib/xos-genx/xos-genx-tests/swagger_test.py
similarity index 100%
rename from lib/xos-genx/tests/swagger_test.py
rename to lib/xos-genx/xos-genx-tests/swagger_test.py
diff --git a/lib/xos-genx/tests/target_test.py b/lib/xos-genx/xos-genx-tests/target_test.py
similarity index 100%
rename from lib/xos-genx/tests/target_test.py
rename to lib/xos-genx/xos-genx-tests/target_test.py
diff --git a/lib/xos-genx/tests/test_cli.py b/lib/xos-genx/xos-genx-tests/test_cli.py
similarity index 89%
rename from lib/xos-genx/tests/test_cli.py
rename to lib/xos-genx/xos-genx-tests/test_cli.py
index 89935bc..29098f1 100644
--- a/lib/xos-genx/tests/test_cli.py
+++ b/lib/xos-genx/xos-genx-tests/test_cli.py
@@ -32,9 +32,9 @@
         [XOS-GenX] The CLI entry point should correctly parse params
         """
         args = Args()
-        args.files = ['tests/xproto/test.xproto']
-        args.target = 'tests/xtarget/test.xtarget'
-        args.output = 'tests/out/dir/'
+        args.files = ['lib/xos-genx/xos-genx-tests/xproto/test.xproto']
+        args.target = 'lib/xos-genx/xos-genx-tests/xtarget/test.xtarget'
+        args.output = 'lib/xos-genx/xos-genx-tests/out/dir/'
         args.write_to_file = "target"
         args.dest_file = None
         args.dest_extension = None
diff --git a/lib/xos-genx/tests/test_generator.py b/lib/xos-genx/xos-genx-tests/test_generator.py
similarity index 98%
rename from lib/xos-genx/tests/test_generator.py
rename to lib/xos-genx/xos-genx-tests/test_generator.py
index 0e7e337..f59bbfd 100644
--- a/lib/xos-genx/tests/test_generator.py
+++ b/lib/xos-genx/xos-genx-tests/test_generator.py
@@ -45,6 +45,7 @@
     """
 
     def setUp(self):
+        os.chdir(os.path.join(os.path.abspath(os.path.dirname(os.path.realpath(__file__))), "..")) 
         filesToRemove = [f for f in os.listdir(OUTPUT_DIR)]
         for f in filesToRemove:
             if not f.startswith('.'):
diff --git a/lib/xos-genx/tests/tosca_test.py b/lib/xos-genx/xos-genx-tests/tosca_test.py
similarity index 100%
rename from lib/xos-genx/tests/tosca_test.py
rename to lib/xos-genx/xos-genx-tests/tosca_test.py
diff --git a/lib/xos-genx/tests/translator_test.py b/lib/xos-genx/xos-genx-tests/translator_test.py
similarity index 100%
rename from lib/xos-genx/tests/translator_test.py
rename to lib/xos-genx/xos-genx-tests/translator_test.py
diff --git a/lib/xos-genx/tests/xos_security_test.py b/lib/xos-genx/xos-genx-tests/xos_security_test.py
similarity index 100%
rename from lib/xos-genx/tests/xos_security_test.py
rename to lib/xos-genx/xos-genx-tests/xos_security_test.py
diff --git a/lib/xos-genx/tests/xos_validation_test.py b/lib/xos-genx/xos-genx-tests/xos_validation_test.py
similarity index 100%
rename from lib/xos-genx/tests/xos_validation_test.py
rename to lib/xos-genx/xos-genx-tests/xos_validation_test.py
diff --git a/lib/xos-genx/tests/xproto/base.xproto b/lib/xos-genx/xos-genx-tests/xproto/base.xproto
similarity index 100%
rename from lib/xos-genx/tests/xproto/base.xproto
rename to lib/xos-genx/xos-genx-tests/xproto/base.xproto
diff --git a/lib/xos-genx/tests/xproto/skip_django.xproto b/lib/xos-genx/xos-genx-tests/xproto/skip_django.xproto
similarity index 100%
rename from lib/xos-genx/tests/xproto/skip_django.xproto
rename to lib/xos-genx/xos-genx-tests/xproto/skip_django.xproto
diff --git a/lib/xos-genx/tests/xproto/test.xproto b/lib/xos-genx/xos-genx-tests/xproto/test.xproto
similarity index 100%
rename from lib/xos-genx/tests/xproto/test.xproto
rename to lib/xos-genx/xos-genx-tests/xproto/test.xproto
diff --git a/lib/xos-genx/tests/xproto/vrouterport.xproto b/lib/xos-genx/xos-genx-tests/xproto/vrouterport.xproto
similarity index 100%
rename from lib/xos-genx/tests/xproto/vrouterport.xproto
rename to lib/xos-genx/xos-genx-tests/xproto/vrouterport.xproto
diff --git a/lib/xos-genx/tests/xtarget/split.xtarget b/lib/xos-genx/xos-genx-tests/xtarget/split.xtarget
similarity index 100%
rename from lib/xos-genx/tests/xtarget/split.xtarget
rename to lib/xos-genx/xos-genx-tests/xtarget/split.xtarget
diff --git a/lib/xos-genx/tests/xtarget/test.xtarget b/lib/xos-genx/xos-genx-tests/xtarget/test.xtarget
similarity index 100%
rename from lib/xos-genx/tests/xtarget/test.xtarget
rename to lib/xos-genx/xos-genx-tests/xtarget/test.xtarget
diff --git a/nose2-plugins/__init__.py b/nose2-plugins/__init__.py
new file mode 100644
index 0000000..42722a8
--- /dev/null
+++ b/nose2-plugins/__init__.py
@@ -0,0 +1,14 @@
+
+# Copyright 2017-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/nose2-plugins/exclude.py b/nose2-plugins/exclude.py
new file mode 100644
index 0000000..241eadb
--- /dev/null
+++ b/nose2-plugins/exclude.py
@@ -0,0 +1,32 @@
+
+# Copyright 2017-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import logging
+import os
+
+from nose2.events import Plugin
+
+log = logging.getLogger('nose2.plugins.excludeignoredfiles')
+
+class ExcludeIgnoredFiles(Plugin):
+    commandLineSwitch = (None, 'exclude-ignored-files', 'Exclude that which should be excluded')
+
+    def matchPath(self, event):
+        if event.path.endswith(".py"):
+            text = open(event.path, "r").read()
+            if "test_framework: ignore" in text.lower():
+                log.info("Ignoring %s" % event.path)
+                event.handled = True
+                return False
diff --git a/unittest.cfg b/unittest.cfg
new file mode 100644
index 0000000..7ca4d6b
--- /dev/null
+++ b/unittest.cfg
@@ -0,0 +1,5 @@
+[unittest]
+plugins=nose2-plugins.exclude
+code-directories=xos-genx
+                 xos-config
+
diff --git a/xos/__init__.py b/xos/__init__.py
new file mode 100644
index 0000000..42722a8
--- /dev/null
+++ b/xos/__init__.py
@@ -0,0 +1,14 @@
+
+# Copyright 2017-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/xos/core/tests.py b/xos/core/tests.py
index 4720865..2c115e0 100644
--- a/xos/core/tests.py
+++ b/xos/core/tests.py
@@ -13,6 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# TEST_FRAMEWORK: IGNORE
 
 # TEST
 # To execute these tests use `python manage.py test core`
@@ -350,4 +351,4 @@
         self.assertEqual(response.status_code, status.HTTP_200_OK)
         model = Service.objects.get(id=self.service1.id)
         self.assertEqual(model.name, data['name'])
-        
\ No newline at end of file
+        
diff --git a/xos/synchronizers/new_base/model_policies/test_config.yaml b/xos/synchronizers/new_base/model_policies/test_config.yaml
index 0fd317f..bffe809 100644
--- a/xos/synchronizers/new_base/model_policies/test_config.yaml
+++ b/xos/synchronizers/new_base/model_policies/test_config.yaml
@@ -18,4 +18,13 @@
 accessor:
   username: xosadmin@opencord.org
   password: "sample"
-  kind: testframework
\ No newline at end of file
+  kind: testframework
+logging:
+  version: 1
+  handlers:
+    console:
+      class: logging.StreamHandler
+  loggers:
+    'multistructlog':
+      handlers:
+          - console
diff --git a/xos/synchronizers/new_base/model_policies/test_model_policy_tenantwithcontainer.py b/xos/synchronizers/new_base/model_policies/test_model_policy_tenantwithcontainer.py
index ec2f4c4..5ea9d77 100644
--- a/xos/synchronizers/new_base/model_policies/test_model_policy_tenantwithcontainer.py
+++ b/xos/synchronizers/new_base/model_policies/test_model_policy_tenantwithcontainer.py
@@ -20,16 +20,11 @@
 import pdb
 
 import os, sys
-sys.path.append("../../..")
-sys.path.append("../../new_base/model_policies")
-config = basic_conf = os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + "/test_config.yaml")
 from xosconfig import Config
-Config.init(config, 'synchronizer-config-schema.yaml')
 
-import synchronizers.new_base.modelaccessor
-
-import model_policy_tenantwithcontainer
-from model_policy_tenantwithcontainer import TenantWithContainerPolicy, LeastLoadedNodeScheduler
+TEST_PATH=os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
+sys.path.append(os.path.join(TEST_PATH, "../../.."))
+sys.path.append(os.path.join(TEST_PATH, "../../new_base/model_policies"))
 
 class MockObject:
     objects = None
@@ -75,6 +70,15 @@
 
 class TestModelPolicyTenantWithContainer(unittest.TestCase):
     def setUp(self):
+        global TenantWithContainerPolicy, LeastLoadedNodeScheduler
+
+        config = basic_conf = os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + "/test_config.yaml")
+        Config.clear() # in case left unclean by a previous test case
+        Config.init(config, 'synchronizer-config-schema.yaml')
+        import synchronizers.new_base.modelaccessor
+        import model_policy_tenantwithcontainer
+        from model_policy_tenantwithcontainer import TenantWithContainerPolicy, LeastLoadedNodeScheduler
+
         self.policy = TenantWithContainerPolicy()
         self.user = MockUser(email="testadmin@test.org")
         self.tenant = MockTenant(creator=self.user)
@@ -82,6 +86,9 @@
         model_policy_tenantwithcontainer.Instance = MockInstance
         model_policy_tenantwithcontainer.Flavor = MockFlavor
 
+    def tearDown(self):
+        Config.clear()
+
     @patch.object(MockTenant, "owner")
     def test_manage_container_no_slices(self, owner):
         owner.slices.count.return_value = 0
@@ -91,12 +98,14 @@
 
     @patch.object(MockTenant, "owner")
     @patch.object(MockTenant, "save")
-    @patch.object(TenantWithContainerPolicy, "get_image")
-    @patch.object(LeastLoadedNodeScheduler, "pick")
+    #@patch.object(TenantWithContainerPolicy, "get_image")
+    #@patch.object(LeastLoadedNodeScheduler, "pick")
     @patch.object(MockNode, "site_deployment")
     @patch.object(MockInstance, "save")
     @patch.object(MockInstance, "delete")
-    def test_manage_container(self, instance_delete, instance_save, site_deployment, pick, get_image, tenant_save, owner):
+    def test_manage_container(self, instance_delete, instance_save, site_deployment, tenant_save, owner):
+      with patch.object(TenantWithContainerPolicy, "get_image") as get_image, \
+           patch.object(LeastLoadedNodeScheduler, "pick") as pick:
         # setup mocks
         node = MockNode(hostname="my.node.com")
         slice = MockSlice(name="mysite_test1", default_flavor=self.flavor, default_isolation="vm")
@@ -137,13 +146,15 @@
 
     @patch.object(MockTenant, "owner")
     @patch.object(MockTenant, "save")
-    @patch.object(TenantWithContainerPolicy, "get_image")
-    @patch.object(LeastLoadedNodeScheduler, "pick")
+    #@patch.object(TenantWithContainerPolicy, "get_image")
+    #@patch.object(LeastLoadedNodeScheduler, "pick")
     @patch.object(MockNode, "site_deployment")
     @patch.object(MockInstance, "save")
     @patch.object(MockInstance, "delete")
     @patch.object(MockFlavor, "objects")
-    def test_manage_container_no_m1_small(self, flavor_objects, instance_delete, instance_save, site_deployment, pick, get_image, tenant_save, owner):
+    def test_manage_container_no_m1_small(self, flavor_objects, instance_delete, instance_save, site_deployment, tenant_save, owner):
+      with patch.object(TenantWithContainerPolicy, "get_image") as get_image, \
+                patch.object(LeastLoadedNodeScheduler, "pick") as pick:
         # setup mocks
         node = MockNode(hostname="my.node.com")
         slice = MockSlice(name="mysite_test1", default_flavor=None, default_isolation="vm")
diff --git a/xos/synchronizers/new_base/tests/test_controller_dependencies.py b/xos/synchronizers/new_base/tests/test_controller_dependencies.py
index f5deb84..8b75579 100644
--- a/xos/synchronizers/new_base/tests/test_controller_dependencies.py
+++ b/xos/synchronizers/new_base/tests/test_controller_dependencies.py
@@ -13,6 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# TEST_FRAMEWORK: IGNORE
 
 import unittest
 from mock import patch
diff --git a/xos/synchronizers/new_base/tests/test_load.py b/xos/synchronizers/new_base/tests/test_load.py
index 8f75f03..b33dd4f 100644
--- a/xos/synchronizers/new_base/tests/test_load.py
+++ b/xos/synchronizers/new_base/tests/test_load.py
@@ -13,6 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# TEST_FRAMEWORK: IGNORE
 
 import unittest
 from mock import patch
diff --git a/xos/synchronizers/new_base/tests/test_payload.py b/xos/synchronizers/new_base/tests/test_payload.py
index 7440c99..c130c50 100644
--- a/xos/synchronizers/new_base/tests/test_payload.py
+++ b/xos/synchronizers/new_base/tests/test_payload.py
@@ -13,6 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# TEST_FRAMEWORK: IGNORE
 
 import unittest
 from mock import patch
diff --git a/xos/synchronizers/new_base/tests/test_run.py b/xos/synchronizers/new_base/tests/test_run.py
index 3a52449..d8512d9 100644
--- a/xos/synchronizers/new_base/tests/test_run.py
+++ b/xos/synchronizers/new_base/tests/test_run.py
@@ -13,6 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# TEST_FRAMEWORK: IGNORE
 
 import unittest
 from mock import patch
diff --git a/xos/synchronizers/new_base/tests/test_scheduler.py b/xos/synchronizers/new_base/tests/test_scheduler.py
index db1698a..a2bfd96 100644
--- a/xos/synchronizers/new_base/tests/test_scheduler.py
+++ b/xos/synchronizers/new_base/tests/test_scheduler.py
@@ -13,6 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# TEST_FRAMEWORK: IGNORE
 
 import unittest
 from mock import patch
diff --git a/xos/synchronizers/new_base/tests/test_services.py b/xos/synchronizers/new_base/tests/test_services.py
index 418b36e..20d52ea 100644
--- a/xos/synchronizers/new_base/tests/test_services.py
+++ b/xos/synchronizers/new_base/tests/test_services.py
@@ -13,6 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# TEST_FRAMEWORK: IGNORE
 
 import unittest
 from mock import patch
diff --git a/xos/xos/tests.py b/xos/xos/tests.py
index 843cf15..c708c0a 100644
--- a/xos/xos/tests.py
+++ b/xos/xos/tests.py
@@ -13,6 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# TEST_FRAMEWORK: IGNORE
 
 """
 This file demonstrates writing tests using the unittest module. These will pass
diff --git a/xos/xos_client/__init__.py b/xos/xos_client/__init__.py
new file mode 100644
index 0000000..b0fb0b2
--- /dev/null
+++ b/xos/xos_client/__init__.py
@@ -0,0 +1,13 @@
+# Copyright 2017-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/xos/xos_client/xosapi/orm_test.py b/xos/xos_client/xosapi/test_orm.py
similarity index 84%
rename from xos/xos_client/xosapi/orm_test.py
rename to xos/xos_client/xosapi/test_orm.py
index 61d37b9..17b6636 100644
--- a/xos/xos_client/xosapi/orm_test.py
+++ b/xos/xos_client/xosapi/test_orm.py
@@ -15,25 +15,32 @@
 
 
 import exceptions
+import os
 import random
 import shutil
 import string
 import sys
 import unittest
 
-# Command-line argument of -R will cause this test to use a real grpc server
-# rather than the fake stub.
+# by default, use fake stub rather than real core
+USE_FAKE_STUB=True
 
-if "-R" in sys.argv:
-    USE_FAKE_STUB = False
-    sys.argv.remove("-R")
-    # Note: will leave lots of litter (users, sites, etc) behind in the database
-else:
-    USE_FAKE_STUB = True
+PARENT_DIR=os.path.join(os.path.dirname(__file__), "..")
 
 class TestORM(unittest.TestCase):
+    def setUp(self):
+        if (USE_FAKE_STUB):
+            sys.path.append(PARENT_DIR)
+
+    def tearDown(self):
+        if (USE_FAKE_STUB):
+            sys.path.remove(PARENT_DIR)
+
     def make_coreapi(self):
         if USE_FAKE_STUB:
+            import xosapi.orm
+            from fake_stub import FakeStub, FakeSymDb, FakeObj
+
             stub = FakeStub()
             api = xosapi.orm.ORMStub(stub=stub, package_name = "xos", sym_db = FakeSymDb(), empty = FakeObj, enable_backoff = False)
             return api
@@ -243,35 +250,40 @@
         self.assertEqual(onos_service_cast.leaf_model_name, "ONOSService")
         self.assertEqual(onos_service_cast.id, onos_service.id)
 
+def main():
+    global USE_FAKE_STUB
+    global xos_grpc_client
 
+    # Command-line argument of -R will cause this test to use a real grpc server
+    # rather than the fake stub.
 
-if USE_FAKE_STUB:
-    sys.path.append("..")
+    if "-R" in sys.argv:
+        USE_FAKE_STUB = False
+        sys.argv.remove("-R")
+        # Note: will leave lots of litter (users, sites, etc) behind in the database
 
-    import xosapi.orm
-    from fake_stub import FakeStub, FakeSymDb, FakeObj
+    if USE_FAKE_STUB:
+        unittest.main()
+    else:
+        # This assumes xos-client python library is installed, and a gRPC server
+        # is available.
 
-    print "Using Fake Stub"
+        from twisted.internet import reactor
+        from xosapi import xos_grpc_client
 
-    unittest.main()
-else:
-    # This assumes xos-client python library is installed, and a gRPC server
-    # is available.
+        print "Using xos-client library and core server"
 
-    from twisted.internet import reactor
-    from xosapi import xos_grpc_client
+        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
+                exitStatus = e.code
 
-    print "Using xos-client library and core server"
+        xos_grpc_client.start_api_parseargs(test_callback)
 
-    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
-            exitStatus = e.code
+        sys.exit(exitStatus)
 
-    xos_grpc_client.start_api_parseargs(test_callback)
-
-    sys.exit(exitStatus)
-
+if __name__ == "__main__":
+    main()
diff --git a/xos/xos_client/xosapi/wrapper_test.py b/xos/xos_client/xosapi/test_wrapper.py
similarity index 75%
rename from xos/xos_client/xosapi/wrapper_test.py
rename to xos/xos_client/xosapi/test_wrapper.py
index ef230b2..0ce9e73 100644
--- a/xos/xos_client/xosapi/wrapper_test.py
+++ b/xos/xos_client/xosapi/test_wrapper.py
@@ -15,6 +15,7 @@
 
 
 import exceptions
+import os
 import random
 import shutil
 import string
@@ -26,16 +27,25 @@
 
 # TODO: Investigate writing wrapper unit tests using mocks rather than using the ORM test framework
 
-if "-R" in sys.argv:
-    USE_FAKE_STUB = False
-    sys.argv.remove("-R")
-    # Note: will leave lots of litter (users, sites, etc) behind in the database
-else:
-    USE_FAKE_STUB = True
+# by default, use fake stub rather than real core
+USE_FAKE_STUB=True
+
+PARENT_DIR=os.path.join(os.path.dirname(__file__), "..")
 
 class TestWrappers(unittest.TestCase):
+    def setUp(self):
+        if (USE_FAKE_STUB):
+            sys.path.append(PARENT_DIR)
+
+    def tearDown(self):
+        if (USE_FAKE_STUB):
+            sys.path.remove(PARENT_DIR)
+
     def make_coreapi(self):
         if USE_FAKE_STUB:
+            import xosapi.orm
+            from fake_stub import FakeStub, FakeSymDb, FakeObj
+
             stub = FakeStub()
             api = xosapi.orm.ORMStub(stub=stub, package_name = "xos", sym_db = FakeSymDb(), empty = FakeObj, enable_backoff = False)
             return api
@@ -114,33 +124,40 @@
 
         self.assertEqual(service_one.get_service_instance_class().model_name, "ServiceInstance")
 
-if USE_FAKE_STUB:
-    sys.path.append("..")
+def main():
+    global USE_FAKE_STUB
+    global xos_grpc_client
 
-    import xosapi.orm
-    from fake_stub import FakeStub, FakeSymDb, FakeObj
+    # Command-line argument of -R will cause this test to use a real grpc server
+    # rather than the fake stub.
 
-    print "Using Fake Stub"
+    if "-R" in sys.argv:
+        USE_FAKE_STUB = False
+        sys.argv.remove("-R")
+        # Note: will leave lots of litter (users, sites, etc) behind in the database
 
-    unittest.main()
-else:
-    # This assumes xos-client python library is installed, and a gRPC server
-    # is available.
+    if USE_FAKE_STUB:
+        unittest.main()
+    else:
+        # This assumes xos-client python library is installed, and a gRPC server
+        # is available.
 
-    from twisted.internet import reactor
-    from xosapi import xos_grpc_client
+        from twisted.internet import reactor
+        from xosapi import xos_grpc_client
 
-    print "Using xos-client library and core server"
+        print "Using xos-client library and core server"
 
-    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
-            exitStatus = e.code
+        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
+                exitStatus = e.code
 
-    xos_grpc_client.start_api_parseargs(test_callback)
+        xos_grpc_client.start_api_parseargs(test_callback)
 
-    sys.exit(exitStatus)
+        sys.exit(exitStatus)
 
+if __name__ == "__main__":
+    main()