Repository: multiply-org/multiply-ui

Issue:
add server options
- [ ] port
- [ ] address

Comments:

Patch:
diff --git a/multiply_ui/server/cli.py b/multiply_ui/server/cli.py
index 0e45d2e..5be1f02 100644
--- a/multiply_ui/server/cli.py
+++ b/multiply_ui/server/cli.py
@@ -1,20 +1,32 @@
-import logging
 import signal
 import sys
 
-import tornado.ioloop
-import tornado.log
-import tornado.web
+import click
 
-from multiply_ui.server.app import new_application
-from multiply_ui.server.context import ServiceContext
+DEFAULT_SERVER_PORT = 9090
+DEFAULT_SERVER_ADDRESS = '0.0.0.0'
 
-PORT = 9090
 
-LOGGER = logging.getLogger('multiply_ui')
+@click.command('mui-server')
+@click.option('--port', '-p',
+              type=int, default=DEFAULT_SERVER_PORT,
+              help=f'Set service port number. Defaults to {DEFAULT_SERVER_PORT}.')
+@click.option('--address', '-a',
+              type=str, default=DEFAULT_SERVER_ADDRESS,
+              help=f'Set service IP address. Defaults to "{DEFAULT_SERVER_ADDRESS}".')
+def mui_server(port, address):
+    """
+    Starts a service which exposes a RESTful API to the Multiply UI.
+    """
 
+    from multiply_ui.server.app import new_application
+    from multiply_ui.server.config import LOGGER
+    from multiply_ui.server.context import ServiceContext
+
+    import tornado.ioloop
+    import tornado.log
+    import tornado.web
 
-def main():
     def shut_down():
         LOGGER.info(f"Shutting down...")
         tornado.ioloop.IOLoop.current().stop()
@@ -25,17 +37,25 @@ def main():
         LOGGER.warning(f'Caught signal {sig}')
         tornado.ioloop.IOLoop.current().add_callback_from_signal(shut_down)
 
-    signal.signal(signal.SIGINT, sig_handler)
-    signal.signal(signal.SIGTERM, sig_handler)
+    def register_termination_handlers():
+        signal.signal(signal.SIGINT, sig_handler)
+        signal.signal(signal.SIGTERM, sig_handler)
 
     tornado.log.enable_pretty_logging()
+
     application = new_application()
     application._ctx = ServiceContext()
-    application.listen(PORT)
+    application.listen(port, address)
+
+    tornado.ioloop.IOLoop.current().add_callback_from_signal(register_termination_handlers)
 
-    LOGGER.info(f"Server listening on port {PORT}...")
+    LOGGER.info(f"Server listening on port {port} at address {address}...")
     tornado.ioloop.IOLoop.current().start()
 
 
-if __name__ == "__main__":
+def main(args=None):
+    mui_server.main(args=args)
+
+
+if __name__ == '__main__':
     main()


Test patch:
diff --git a/test/server/test_cli.py b/test/server/test_cli.py
new file mode 100644
index 0000000..2abab7e
--- /dev/null
+++ b/test/server/test_cli.py
@@ -0,0 +1,28 @@
+import unittest
+
+import click.testing
+
+from multiply_ui.server.cli import mui_server
+
+
+class CliTest(unittest.TestCase):
+    @classmethod
+    def invoke_cli(cls, *args):
+        runner = click.testing.CliRunner()
+        return runner.invoke(mui_server, args, catch_exceptions=False)
+
+    def test_help_option(self):
+        result = self.invoke_cli('--help')
+        self.assertEqual(0, result.exit_code)
+        self.assertEqual(
+            (
+                'Usage: mui-server [OPTIONS]\n'
+                '\n'
+                '  Starts a service which exposes a RESTful API to the Multiply UI.\n'
+                '\n'
+                'Options:\n'
+                '  -p, --port INTEGER  Set service port number. Defaults to 9090.\n'
+                '  -a, --address TEXT  Set service IP address. Defaults to "0.0.0.0".\n'
+                '  --help              Show this message and exit.\n'
+            ),
+            result.stdout)
diff --git a/test/server/test_controller.py b/test/server/test_controller.py
index d8fb105..5562556 100644
--- a/test/server/test_controller.py
+++ b/test/server/test_controller.py
@@ -1,9 +1,10 @@
-import multiply_ui.server.controller as controller
 import json
-import multiply_ui.server.context as context
 import os
 import unittest
 
+from multiply_ui.server import controller
+
+
 class ControllerTest(unittest.TestCase):
 
     def test_get_parameters(self):
@@ -13,6 +14,7 @@ class ControllerTest(unittest.TestCase):
 
     @unittest.skipIf(os.environ.get('MULTIPLY_DISABLE_WEB_TESTS') == '1', 'MULTIPLY_DISABLE_WEB_TESTS = 1')
     def test_get_inputs(self):
+        from multiply_ui.server import context
         with open(os.path.join(os.path.dirname(__file__), '..', 'test_data', 'example_request_parameters.json')) as fp:
             json_text = fp.read()
             parameters = json.loads(json_text)