Beispiel #1
0
class ScriptCheckEndpointDoesNotExistTest(tornado.testing.AsyncHTTPTestCase):
    async def does_script_run_without_error(self):
        self.fail("Should not be called")

    def setUp(self):
        self._server = Server(None, None, "test command line")
        self._server.does_script_run_without_error = self.does_script_run_without_error
        self._old_config = config.get_option("server.scriptHealthCheckEnabled")
        config._set_option("server.scriptHealthCheckEnabled", False, "test")
        super().setUp()

    def tearDown(self):
        config._set_option("server.scriptHealthCheckEnabled", self._old_config,
                           "test")
        Server._singleton = None
        super().tearDown()

    def get_app(self):
        return self._server._create_app()

    def test_endpoint(self):
        response = self.fetch("/script-health-check")
        self.assertEqual(404, response.code)
Beispiel #2
0
class ServerTestCase(tornado.testing.AsyncHTTPTestCase):
    """Base class for async streamlit.server testing.

    Subclasses should patch 'streamlit.server.server.AppSession',
    to prevent AppSessions from being created, and scripts from
    being run. (Script running involves creating new threads, which
    interfere with other tests if not properly terminated.)

    See the "ServerTest" class for example usage.
    """

    _next_session_id = 0

    def get_app(self):
        # Create a Server, and patch its _on_stopped function
        # to no-op. This prevents it from shutting down the
        # ioloop when it stops.
        self.server = Server(self.io_loop, "/not/a/script.py",
                             "test command line")
        self.server._on_stopped = mock.MagicMock()  # type: ignore[assignment]
        app = self.server._create_app()
        return app

    def tearDown(self):
        super(ServerTestCase, self).tearDown()
        # Clear the Server singleton for the next test
        Server._singleton = None

    def start_server_loop(self):
        """Starts the server's loop coroutine.

        Returns
        -------
        Future
            A Future that resolves when the loop has started.
            You need to yield on this value from within a
            'tornado.testing.gen_test' coroutine.

        """
        server_started = Future()  # type: ignore[var-annotated]
        self.io_loop.spawn_callback(self.server._loop_coroutine,
                                    lambda _: server_started.set_result(None))
        return server_started

    def get_ws_url(self, path):
        """Return a ws:// URL with the given path for our test server."""
        # get_url() gives us a result with the 'http' scheme;
        # we swap it out for 'ws'.
        url = self.get_url(path)
        parts = list(urllib.parse.urlparse(url))
        parts[0] = "ws"
        return urllib.parse.urlunparse(tuple(parts))

    def ws_connect(self):
        """Open a websocket connection to the server.

        Returns
        -------
        Future
            A Future that resolves with the connected websocket client.
            You need to yield on this value from within a
            'tornado.testing.gen_test' coroutine.

        """
        return tornado.websocket.websocket_connect(self.get_ws_url("/stream"))

    @tornado.gen.coroutine
    def read_forward_msg(self, ws_client):
        """Parse the next message from a Websocket client into a ForwardMsg."""
        data = yield ws_client.read_message()
        message = ForwardMsg()
        message.ParseFromString(data)
        raise gen.Return(message)

    @staticmethod
    def _create_mock_app_session(*args, **kwargs):
        """Create a mock AppSession. Each mocked instance will have
        its own unique ID."""
        mock_id = mock.PropertyMock(return_value="mock_id:%s" %
                                    ServerTestCase._next_session_id)
        ServerTestCase._next_session_id += 1

        mock_session = mock.MagicMock(AppSession,
                                      autospec=True,
                                      *args,
                                      **kwargs)
        type(mock_session).id = mock_id
        return mock_session

    def _patch_app_session(self):
        """Mock the Server's AppSession import. We don't want
        actual sessions to be instantiated, or scripts to be run.
        """

        return mock.patch(
            "streamlit.server.server.AppSession",
            # new_callable must return a function, not an object, or else
            # there will only be a single AppSession mock. Hence the lambda.
            new_callable=lambda: self._create_mock_app_session,
        )
Beispiel #3
0
class ServerTestCase(tornado.testing.AsyncHTTPTestCase):
    """Base class for async streamlit.server testing.

    Subclasses should patch 'streamlit.server.server.ReportSession',
    to prevent ReportSessions from being created, and scripts from
    being run. (Script running involves creating new threads, which
    interfere with other tests if not properly terminated.)

    See the "ServerTest" class for example usage.
    """
    def get_app(self):
        # Create a Server, and patch its _on_stopped function
        # to no-op. This prevents it from shutting down the
        # ioloop when it stops.
        self.server = Server(self.io_loop, "/not/a/script.py",
                             "test command line")
        self.server._on_stopped = mock.MagicMock()  # type: ignore[assignment]
        app = self.server._create_app()
        return app

    def tearDown(self):
        super(ServerTestCase, self).tearDown()
        # Clear the Server singleton for the next test
        Server._singleton = None

    def start_server_loop(self):
        """Starts the server's loop coroutine.

        Returns
        -------
        Future
            A Future that resolves when the loop has started.
            You need to yield on this value from within a
            'tornado.testing.gen_test' coroutine.

        """
        server_started = Future()  # type: ignore[var-annotated]
        self.io_loop.spawn_callback(self.server._loop_coroutine,
                                    lambda _: server_started.set_result(None))
        return server_started

    def get_ws_url(self, path):
        """Return a ws:// URL with the given path for our test server."""
        # get_url() gives us a result with the 'http' scheme;
        # we swap it out for 'ws'.
        url = self.get_url(path)
        parts = list(urllib.parse.urlparse(url))
        parts[0] = "ws"
        return urllib.parse.urlunparse(tuple(parts))

    def ws_connect(self):
        """Open a websocket connection to the server.

        Returns
        -------
        Future
            A Future that resolves with the connected websocket client.
            You need to yield on this value from within a
            'tornado.testing.gen_test' coroutine.

        """
        return tornado.websocket.websocket_connect(self.get_ws_url("/stream"))

    @tornado.gen.coroutine
    def read_forward_msg(self, ws_client):
        """Parse the next message from a Websocket client into a ForwardMsg."""
        data = yield ws_client.read_message()
        message = ForwardMsg()
        message.ParseFromString(data)
        raise gen.Return(message)