=== modified file '.bzrignore'
--- .bzrignore	2011-09-12 09:19:10 +0000
+++ .bzrignore	2012-02-04 20:53:31 +0000
@@ -1,8 +1,7 @@
+*.egg
+*.egg-info
+*.tmp
 .idea
 .testrepository
+build
 dist
-lava_test.egg-info
-*~
-*.tmp
-*.py[co]
-build

=== removed file '.testr.conf'
--- .testr.conf	2010-06-14 20:32:28 +0000
+++ .testr.conf	1970-01-01 00:00:00 +0000
@@ -1,3 +0,0 @@
-[DEFAULT]
-test_command=PYTHONPATH=. python -m subunit.run $IDLIST
-test_id_list_default=tests.test_suite

=== modified file 'MANIFEST.in'
--- MANIFEST.in	2011-09-12 09:19:10 +0000
+++ MANIFEST.in	2012-02-06 15:47:49 +0000
@@ -1,3 +1,2 @@
 include COPYING
 include README
-include .testr.conf

=== modified file 'lava_test/core/providers.py'
--- lava_test/core/providers.py	2012-01-18 21:45:51 +0000
+++ lava_test/core/providers.py	2012-02-06 17:51:19 +0000
@@ -172,19 +172,18 @@
                 if test.test_id in self._cache:
                     raise ValueError("Duplicate test %s declared" % test.test_id)
                 self._cache[test.test_id] = test
-            except IOError, err:
-                logging.warning("Failed to load the " + test_url)
-                if hasattr(e, 'reason'):
-                    logging.warning("WARNING: URL Reason: "+ e.reason)
-                elif hasattr(e, 'code'):
-                    logging.warning('WARNING: URL Error code: ' + e.code)
-                else:
-                    logging.exception("WARNING: Unknown IO error", str(err))
-            except ValueError, err:
-                logging.warning('Error found when parsing the' + test_url)
-            except Exception, err:
-                logging.warning('Failed to load the' + test_url)
-                logging.warning("Unknown exception : " + str(err))
+            except IOError as exc:
+                logging.warning(
+                    "Unable to load test definition from %r: %r", test_url, exc)
+                if hasattr(exc, 'reason'):
+                    logging.warning("Error reason: %r", exc.reason)
+                elif hasattr(exc, 'code'):
+                    logging.warning('Error code: %r', exc.code)
+            except Exception as exc:
+                # This can be a number of things, including URL errors, JSON
+                # errors and validation errors
+                logging.warning('Unable to load test definition from %r: %r', 
+                                test_url, exc)
 
     def __iter__(self):
         self._fill_cache()

=== modified file 'setup.py'
--- setup.py	2011-09-12 09:19:10 +0000
+++ setup.py	2012-02-06 15:48:33 +0000
@@ -28,7 +28,7 @@
     long_description=open("README").read(),
     packages=find_packages(exclude=['tests']),
     license="GNU GPLv3",
-    test_suite='tests.test_suite',
+    test_suite='unittest2.collector',
     entry_points="""
     [console_scripts]
     lava-test=lava_test.main:main
@@ -60,5 +60,9 @@
     setup_requires=[
         'versiontools >= 1.4'
     ],
+    tests_require=[
+        'unittest2',
+        'mocker >= 1.1',
+    ],
     zip_safe=False,
     include_package_data=True)

=== modified file 'tests/__init__.py'
--- tests/__init__.py	2011-09-12 09:19:10 +0000
+++ tests/__init__.py	2012-02-04 20:50:16 +0000
@@ -12,17 +12,3 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-import unittest
-
-def test_suite():
-    module_names = ['tests.test_lavatest_commands',
-                    'tests.test_lavatest_test',
-                    'tests.test_lavatest_testinstaller',
-                    'tests.test_lavatest_testparser',
-                    'tests.test_lavatest_testrunner',
-                    'tests.test_hwprofile',
-                    'tests.test_swprofile']
-    loader = unittest.TestLoader()
-    suite = loader.loadTestsFromNames(module_names)
-    return suite

=== added file 'tests/test_providers.py'
--- tests/test_providers.py	1970-01-01 00:00:00 +0000
+++ tests/test_providers.py	2012-02-06 17:51:19 +0000
@@ -0,0 +1,105 @@
+# Copyright (c) 2012 Linaro Limited
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+from mocker import MockerTestCase
+
+from lava_test.core.providers import RegistryProvider
+
+
+class RegistryProviderTests(MockerTestCase):
+
+    # Helper values used in test methods
+    _code = 1
+    _reason = "reason"
+    _test_id = 'test1'
+    _test_id_list = ['test1', 'test2']
+    _url = "http://example.org/test.json"
+
+    def _prepare_provider_that_crashes_with_error(self, error):
+        self.provider = self.mocker.patch(
+            RegistryProvider({'entries': [self._url]}))
+        self.expect(self.provider._fill_cache()).passthrough()
+        self.expect(self.provider._load_remote_test(self._url)).throw(error)
+
+    def _test_fill_cache_response(self):
+        # Now onto testing:
+        self.mocker.replay()
+        # Call _fill_cache()
+        self.provider._fill_cache()
+        # the actual tests are validated as mocker expectation
+
+    def test_fill_cache_IOError_handling_with_just_reason(self):
+        # We want to test resilience to IOError that has a 'reason' attribute
+        error = IOError()
+        error.reason = self._reason
+        self._prepare_provider_that_crashes_with_error(error)
+        # Now this ought to log a few warning messages
+        logging = self.mocker.replace("logging", passthrough=False)
+        logging.warning(
+            "Unable to load test definition from %r: %r",
+            self._url, error)
+        logging.warning("Error reason: %r", self._reason)
+        self._test_fill_cache_response()
+
+    def test_fill_cache_IOError_handling_with_just_code(self):
+        # We want to test resilience to IOError that has a 'code' attribute
+        error = IOError()
+        error.code = self._code
+        provider = self._prepare_provider_that_crashes_with_error(error)
+        # Now this ought to log a few warning messages
+        logging = self.mocker.replace("logging", passthrough=False)
+        logging.warning(
+            "Unable to load test definition from %r: %r",
+            self._url, error)
+        logging.warning("Error code: %r", self._code)
+        self._test_fill_cache_response()
+
+    def test_fill_cache_IOError_handling_without_anything(self):
+        # We want to test resilience to IOError that has no attributes
+        error = IOError()
+        provider = self._prepare_provider_that_crashes_with_error(error)
+        # Now this ought to log a few warning messages
+        logging = self.mocker.replace("logging", passthrough=False)
+        logging.warning(
+            "Unable to load test definition from %r: %r",
+            self._url, error)
+        self._test_fill_cache_response()
+
+    def test_fill_cache_ValueError_handling(self):
+        # We want to test resilience to ValueError 
+        error = ValueError()
+        provider = self._prepare_provider_that_crashes_with_error(error)
+        # Now this ought to log a few warning messages
+        logging = self.mocker.replace("logging", passthrough=False)
+        logging.warning(
+            "Unable to load test definition from %r: %r",
+            self._url, error)
+        self._test_fill_cache_response()
+
+    def test_iter_calls_fill_cache(self):
+        provider = self.mocker.patch(RegistryProvider({}))
+        self.expect(iter(provider)).passthrough()
+        self.expect(provider._fill_cache())
+        self.expect(provider._cache.iterkeys()).generate(self._test_id_list)
+        self.mocker.replay()
+        self.assertSequenceEqual(list(provider), self._test_id_list)
+
+    def test_getitem_calls_fill_cache(self):
+        provider = self.mocker.patch(RegistryProvider({}))
+        self.expect(provider[self._test_id]).passthrough()
+        self.expect(provider._fill_cache())
+        self.expect(provider._cache[self._test_id])
+        self.mocker.replay()
+        provider[self._test_id]

