Repository: simphony/simphony-remote

Issue:
HomeHandler should not 'finish' in View and Stop but raise
Let view and stop raise and then the HomeHandler.post will handle the logging.

https://github.com/simphony/simphony-remote/blob/98ee374756694ef1855a9d38d78d3561ec6cc54e/remoteappmanager/handlers/home_handler.py#L155

https://github.com/simphony/simphony-remote/blob/98ee374756694ef1855a9d38d78d3561ec6cc54e/remoteappmanager/handlers/home_handler.py#L132

Comments:

Patch:
diff --git a/remoteappmanager/cli/remoteappdb/__main__.py b/remoteappmanager/cli/remoteappdb/__main__.py
index ab76d4f..e4144ab 100644
--- a/remoteappmanager/cli/remoteappdb/__main__.py
+++ b/remoteappmanager/cli/remoteappdb/__main__.py
@@ -94,6 +94,24 @@ def get_docker_client():
     return client
 
 
+def is_sqlitedb_url(db_url):
+    """Returns True if the url refers to a sqlite database"""
+    return db_url.startswith("sqlite:///")
+
+
+def sqlitedb_present(db_url):
+    """Checks if the db url is present.
+    Remote urls are always assumed to be present, so this method
+    concerns mostly sqlite databases."""
+
+    if not db_url.startswith("sqlite:///"):
+        raise ValueError("db_url {} does not refer to a "
+                         "sqlite database.".format(db_url))
+
+    path = sqlite_url_to_path(db_url)
+    return os.path.exists(path)
+
+
 class RemoteAppDBContext(object):
     def __init__(self, db_url):
         db_url = normalise_to_url(db_url)
@@ -120,11 +138,9 @@ def init(ctx):
     db_url = db.url
 
     # Check if the database already exists
-    if db_url.startswith("sqlite:///"):
-        path = sqlite_url_to_path(db_url)
-        if os.path.exists(path):
-            raise click.UsageError("Refusing to overwrite database "
-                                   "at {}".format(db_url))
+    if is_sqlitedb_url(db_url) and sqlitedb_present(db_url):
+        raise click.UsageError("Refusing to overwrite database "
+                               "at {}".format(db_url))
     db.reset()
 
 
@@ -133,9 +149,18 @@ def init(ctx):
 
 
 @cli.group()
-def user():
+@click.pass_context
+def user(ctx):
     """Subcommand to manage users."""
-    pass
+    db = ctx.obj.db
+    db_url = db.url
+
+    # sqlite driver for sqlalchemy creates an empty file on commit as a side
+    # effect. We don't want this creation to happen, so before attempting
+    # the creation we stop short if we already find out that the file is
+    # missing and cannot possibly be initialized.
+    if is_sqlitedb_url(db_url) and not sqlitedb_present(db_url):
+        raise click.UsageError("Could not find database at {}".format(db_url))
 
 
 @user.command()
@@ -228,9 +253,14 @@ def list(ctx, no_decoration, show_apps):
 
 
 @cli.group()
-def app():
+@click.pass_context
+def app(ctx):
     """Subcommand to manage applications."""
-    pass
+    db = ctx.obj.db
+    db_url = db.url
+
+    if is_sqlitedb_url(db_url) and not sqlitedb_present(db_url):
+        raise click.UsageError("Could not find database at {}".format(db_url))
 
 
 @app.command()  # noqa
diff --git a/remoteappmanager/handlers/home_handler.py b/remoteappmanager/handlers/home_handler.py
index c21824b..7d5ce97 100644
--- a/remoteappmanager/handlers/home_handler.py
+++ b/remoteappmanager/handlers/home_handler.py
@@ -131,8 +131,10 @@ class HomeHandler(BaseHandler):
         container_manager = self.application.container_manager
         container = yield container_manager.container_from_url_id(url_id)
         if not container:
-            self.finish("Unable to view the application")
-            return
+            self.log.warning("Could not find container for url_id {}".format(
+                url_id
+            ))
+            raise ValueError("Unable to view container for specified url_id")
 
         # make sure the container is actually running and working
         yield self._wait_for_container_ready(container)
@@ -158,8 +160,10 @@ class HomeHandler(BaseHandler):
 
         container = yield container_manager.container_from_url_id(url_id)
         if not container:
-            self.finish("Unable to view the application")
-            return
+            self.log.warning("Could not find container for url_id {}".format(
+                url_id
+            ))
+            raise ValueError("Unable to view container for specified url_id")
 
         urlpath = url_path_join(
             self.application.command_line_config.base_urlpath,
diff --git a/remoteappmanager/spawner.py b/remoteappmanager/spawner.py
index a226fa9..8637879 100644
--- a/remoteappmanager/spawner.py
+++ b/remoteappmanager/spawner.py
@@ -20,7 +20,7 @@ class Spawner(LocalProcessSpawner):
     proxy = Any()
 
     #: The path of the configuration file for the cmd executable
-    config_file_path = Unicode()
+    config_file_path = Unicode(config=True)
 
     def __init__(self, **kwargs):
         super().__init__(**kwargs)


Test patch:
diff --git a/tests/cli/test_remoteappdb.py b/tests/cli/test_remoteappdb.py
index 004a99e..57db987 100644
--- a/tests/cli/test_remoteappdb.py
+++ b/tests/cli/test_remoteappdb.py
@@ -25,9 +25,23 @@ class TestRemoteAppDbCLI(TempMixin, unittest.TestCase):
 
         return result.exit_code, result.output
 
+    def test_is_sqlitedb_url(self):
+        self.assertTrue(remoteappdb.is_sqlitedb_url("sqlite:///foo.db"))
+        self.assertFalse(remoteappdb.is_sqlitedb_url("whatever:///foo.db"))
+
+    def test_sqlite_present(self):
+        self.assertTrue(remoteappdb.sqlitedb_present(
+            "sqlite:///"+self.db))
+        self.assertFalse(remoteappdb.sqlitedb_present(
+            "sqlite:///"+self.db+"whatever"))
+
     def test_init_command(self):
         self.assertTrue(os.path.exists(self.db))
 
+        # This should fail because the database is already present
+        exit_code, output = self._remoteappdb("init")
+        self.assertNotEqual(exit_code, 0)
+
     def test_user_create(self):
         _, out = self._remoteappdb("user create foo")
         self.assertEqual(out, "1\n")
@@ -174,3 +188,13 @@ class TestRemoteAppDbCLI(TempMixin, unittest.TestCase):
         _, out = self._remoteappdb("user list --show-apps --no-decoration")
         self.assertEqual(len(out.split('\n')), 2)
         self.assertNotIn("myapp", out)
+
+    def test_commands_noinit(self):
+        # Remove the conveniently setup database
+        os.remove(self.db)
+
+        exit_code, out = self._remoteappdb("user create foo")
+        self.assertNotEqual(exit_code, 0)
+
+        exit_code, out = self._remoteappdb("app create foo")
+        self.assertNotEqual(exit_code, 0)
diff --git a/tests/handlers/test_home_handler.py b/tests/handlers/test_home_handler.py
index 596b8db..7a49d7f 100644
--- a/tests/handlers/test_home_handler.py
+++ b/tests/handlers/test_home_handler.py
@@ -184,3 +184,34 @@ class TestHomeHandler(TempMixin, utils.AsyncHTTPTestCase):
 
             self.assertTrue(self._app.reverse_proxy.register.called)
             self.assertTrue(redirect.called)
+
+    def test_container_manager_does_not_return_container(self):
+        self._app.container_manager.container_from_url_id = \
+            utils.mock_coro_factory(None)
+        res = self.fetch(
+            "/user/username/",
+            method="POST",
+            headers={
+                "Cookie": "jupyter-hub-token-username=foo"
+            },
+            body=urllib.parse.urlencode({
+                'action': 'view',
+                'url_id': '12345'
+            })
+        )
+
+        self.assertIn("ValueError", str(res.body))
+
+        res = self.fetch(
+            "/user/username/",
+            method="POST",
+            headers={
+                "Cookie": "jupyter-hub-token-username=foo"
+            },
+            body=urllib.parse.urlencode({
+                'action': 'stop',
+                'url_id': '12345'
+            })
+        )
+
+        self.assertIn("ValueError", str(res.body))