Ejemplo n.º 1
0
    def test_defaults_multiline(self):
        out = FakeOutput()
        p = Printer(output=out, env=FakeEnv())
        p.write("one\ntwo\nthree")

        expect = "12:42:00 unknown | one\n12:42:00 unknown | two\n12:42:00 unknown | three"
        self.assertEqual(expect, out.last_write())
Ejemplo n.º 2
0
class TestPrinter(object):
    def setup(self):
        self.out = MagicMock()

        self._dt_patch = patch('honcho.printer.datetime')
        self._dt = self._dt_patch.start()
        self._dt.now.return_value = datetime.datetime(2012, 8, 11, 12, 42)

    def teardown(self):
        self._dt_patch.stop()

    def test_defaults_simple(self):
        self.p = Printer(output=self.out)
        self.p.write("monkeys")
        self.out.write.assert_called_once_with("12:42:00 unknown | monkeys")

    def test_defaults_multiline(self):
        self.p = Printer(output=self.out)
        self.p.write("one\ntwo\nthree")

        expect = "12:42:00 unknown | one\n12:42:00 unknown | two\n12:42:00 unknown | three"
        self.out.write.assert_called_once_with(expect)

    def test_name_simple(self):
        self.p = Printer(output=self.out, name="Robert Louis Stevenson")
        self.p.write("quiescent")
        self.out.write.assert_called_once_with("12:42:00 Robert Louis Stevenson | quiescent")

    def test_length_simple(self):
        self.p = Printer(output=self.out, name="oop", width=6)
        self.p.write("narcissist")
        self.out.write.assert_called_once_with("12:42:00 oop    | narcissist")

    def test_colour_simple(self):
        self.p = Printer(output=self.out, name="red", colour="31")
        self.p.write("conflate")
        self.out.write.assert_called_once_with("\033[31m12:42:00 red | \033[0mconflate")
Ejemplo n.º 3
0
 def test_write_invalid_utf8(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message(b"\xfe\xff\n"))
     assert out.string() == "12:42:00 | \ufffd\ufffd\n"
Ejemplo n.º 4
0
 def test_write(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message("monkeys\n"))
     assert out.string() == "12:42:00 | monkeys\n"
Ejemplo n.º 5
0
 def test_write_without_colour_tty(self):
     out = FakeTTY()
     p = Printer(output=out, prefix=True, colour=False)
     p.write(fake_message("paranoid android\n", name="foo", colour="31"))
     assert out.string() == "12:42:00 foo | paranoid android\n"
Ejemplo n.º 6
0
 def test_write_with_colour(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message("conflate\n", name="foo", colour="31"))
     self.assertEqual("\033[31m12:42:00 foo | \033[0mconflate\n",
                      out.string())
Ejemplo n.º 7
0
 def test_write_with_set_width(self):
     out = FakeOutput()
     p = Printer(output=out, width=6)
     p.write(fake_message("giraffe\n"))
     self.assertEqual("12:42:00        | giraffe\n", out.string())
Ejemplo n.º 8
0
 def test_write_multiline(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message("one\ntwo\nthree\n"))
     expect = "12:42:00 | one\n12:42:00 | two\n12:42:00 | three\n"
     self.assertEqual(expect, out.string())
Ejemplo n.º 9
0
 def test_write(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message("monkeys\n"))
     assert out.string() == "12:42:00 | monkeys\n"
Ejemplo n.º 10
0
 def test_write_with_colour_non_tty(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message("conflate\n", name="foo", colour="31"))
     assert out.string() == "12:42:00 foo | conflate\n"
Ejemplo n.º 11
0
 def test_write_with_colour_tty(self):
     out = FakeTTY()
     p = Printer(output=out)
     p.write(fake_message("conflate\n", name="foo", colour="31"))
     assert out.string() == "\033[0m\033[31m12:42:00 foo | \033[0mconflate\n"
Ejemplo n.º 12
0
 def test_write_without_prefix_non_tty(self):
     out = FakeOutput()
     p = Printer(output=out, prefix=False)
     p.write(fake_message("paranoid android\n", name="foo", colour="31"))
     assert out.string() == "paranoid android\n"
Ejemplo n.º 13
0
 def test_write_without_colour_tty(self):
     out = FakeTTY()
     p = Printer(output=out, prefix=True, colour=False)
     p.write(fake_message("paranoid android\n", name="foo", colour="31"))
     assert out.string() == "12:42:00 foo | paranoid android\n"
Ejemplo n.º 14
0
 def test_write_with_colour_non_tty(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message("conflate\n", name="foo", colour="31"))
     assert out.string() == "12:42:00 foo | conflate\n"
Ejemplo n.º 15
0
 def test_write_with_colour_tty(self):
     out = FakeTTY()
     p = Printer(output=out)
     p.write(fake_message("conflate\n", name="foo", colour="31"))
     assert out.string(
     ) == "\033[0m\033[31m12:42:00 foo | \033[0mconflate\n"
Ejemplo n.º 16
0
 def test_length_simple(self):
     out = FakeOutput()
     p = Printer(output=out, name="oop", width=6, env=FakeEnv())
     p.write("narcissist")
     self.assertEqual("12:42:00 oop    | narcissist", out.last_write())
Ejemplo n.º 17
0
 def test_write_wrong_type(self):
     out = FakeOutput()
     p = Printer(output=out)
     with pytest.raises(RuntimeError):
         p.write(fake_message("monkeys\n", type="error"))
Ejemplo n.º 18
0
 def test_write_no_newline(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message("monkeys"))
     self.assertEqual("12:42:00 | monkeys\n", out.string())
Ejemplo n.º 19
0
 def test_write_with_name(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message("quiescent\n", name="Robert Louis Stevenson"))
     self.assertEqual("12:42:00 Robert Louis Stevenson | quiescent\n",
                      out.string())
Ejemplo n.º 20
0
 def test_write_multiline(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message("one\ntwo\nthree\n"))
     expect = "12:42:00 | one\n12:42:00 | two\n12:42:00 | three\n"
     self.assertEqual(expect, out.string())
Ejemplo n.º 21
0
 def test_write_with_name_and_set_width(self):
     out = FakeOutput()
     p = Printer(output=out, width=6)
     p.write(fake_message("narcissist\n", name="oop"))
     self.assertEqual("12:42:00 oop    | narcissist\n", out.string())
Ejemplo n.º 22
0
 def test_write_with_name(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message("quiescent\n", name="Robert Louis Stevenson"))
     self.assertEqual("12:42:00 Robert Louis Stevenson | quiescent\n",
                      out.string())
Ejemplo n.º 23
0
def devserver(
    reload,
    watchers,
    workers,
    ingest,
    experimental_spa,
    styleguide,
    prefix,
    pretty,
    environment,
    debug_server,
    bind,
):
    "Starts a lightweight web server for development."

    if bind is None:
        bind = "127.0.0.1:8000"

    if ":" in bind:
        host, port = bind.split(":", 1)
        port = int(port)
    else:
        host = bind
        port = None

    import os

    os.environ["SENTRY_ENVIRONMENT"] = environment
    # NODE_ENV *must* use production for any prod-like environment as third party libraries look
    # for this magic constant
    os.environ["NODE_ENV"] = "production" if environment.startswith(
        "prod") else environment

    from django.conf import settings

    from sentry import options
    from sentry.services.http import SentryHTTPServer

    url_prefix = options.get("system.url-prefix", "")
    parsed_url = urlparse(url_prefix)
    # Make sure we're trying to use a port that we can actually bind to
    needs_https = parsed_url.scheme == "https" and (parsed_url.port
                                                    or 443) > 1024
    has_https = False

    if needs_https:
        from subprocess import check_output

        try:
            check_output(["which", "https"])
            has_https = True
        except Exception:
            has_https = False
            from sentry.runner.initializer import show_big_error

            show_big_error([
                "missing `https` on your `$PATH`, but https is needed",
                "`$ brew install mattrobenolt/stuff/https`",
            ])

    uwsgi_overrides = {
        "http-keepalive": True,
        # Make sure we reload really quickly for local dev in case it
        # doesn't want to shut down nicely on it's own, NO MERCY
        "worker-reload-mercy": 2,
        # We need stdin to support pdb in devserver
        "honour-stdin": True,
        # accept ridiculously large files
        "limit-post": 1 << 30,
        # do something with chunked
        "http-chunked-input": True,
        "thunder-lock": False,
        "timeout": 600,
        "harakiri": 600,
    }

    if reload:
        uwsgi_overrides["py-autoreload"] = 1

    daemons = []

    if experimental_spa:
        os.environ["SENTRY_UI_DEV_ONLY"] = "1"
        if not watchers:
            click.secho(
                "Using experimental SPA mode without watchers enabled has no effect",
                err=True,
                fg="yellow",
            )

    # We proxy all requests through webpacks devserver on the configured port.
    # The backend is served on port+1 and is proxied via the webpack
    # configuration.
    if watchers:
        daemons += settings.SENTRY_WATCHERS

        proxy_port = port
        port = port + 1

        uwsgi_overrides["protocol"] = "http"

        os.environ["FORCE_WEBPACK_DEV_SERVER"] = "1"
        os.environ["SENTRY_WEBPACK_PROXY_HOST"] = "%s" % host
        os.environ["SENTRY_WEBPACK_PROXY_PORT"] = "%s" % proxy_port
        os.environ["SENTRY_BACKEND_PORT"] = "%s" % port

        # webpack and/or typescript is causing memory issues
        os.environ["NODE_OPTIONS"] = (os.environ.get("NODE_OPTIONS", "") +
                                      " --max-old-space-size=4096").lstrip()
    else:
        # If we are the bare http server, use the http option with uwsgi protocol
        # See https://uwsgi-docs.readthedocs.io/en/latest/HTTP.html
        uwsgi_overrides.update({
            # Make sure uWSGI spawns an HTTP server for us as we don't
            # have a proxy/load-balancer in front in dev mode.
            "http": f"{host}:{port}",
            "protocol": "uwsgi",
            # This is needed to prevent https://git.io/fj7Lw
            "uwsgi-socket": None,
        })

    if ingest in (True, False):
        settings.SENTRY_USE_RELAY = ingest

    os.environ["SENTRY_USE_RELAY"] = "1" if settings.SENTRY_USE_RELAY else ""

    if workers:
        if settings.CELERY_ALWAYS_EAGER:
            raise click.ClickException(
                "Disable CELERY_ALWAYS_EAGER in your settings file to spawn workers."
            )

        daemons += [_get_daemon("worker"), _get_daemon("cron")]

        from sentry import eventstream

        if eventstream.requires_post_process_forwarder():
            daemons += [_get_daemon("post-process-forwarder")]

        if settings.SENTRY_EXTRA_WORKERS:
            daemons.extend(
                [_get_daemon(name) for name in settings.SENTRY_EXTRA_WORKERS])

        if settings.SENTRY_DEV_PROCESS_SUBSCRIPTIONS:
            if not settings.SENTRY_EVENTSTREAM == "sentry.eventstream.kafka.KafkaEventStream":
                raise click.ClickException(
                    "`SENTRY_DEV_PROCESS_SUBSCRIPTIONS` can only be used when "
                    "`SENTRY_EVENTSTREAM=sentry.eventstream.kafka.KafkaEventStream`."
                )
            for name, topic in settings.KAFKA_SUBSCRIPTION_RESULT_TOPICS.items(
            ):
                daemons += [
                    _get_daemon("subscription-consumer",
                                "--topic",
                                topic,
                                suffix=name)
                ]

        if settings.SENTRY_USE_METRICS_DEV and settings.SENTRY_USE_RELAY:
            if not settings.SENTRY_EVENTSTREAM == "sentry.eventstream.kafka.KafkaEventStream":
                # The metrics indexer produces directly to kafka, so it makes
                # no sense to run it with SnubaEventStream.
                raise click.ClickException(
                    "`SENTRY_USE_METRICS_DEV` can only be used when "
                    "`SENTRY_EVENTSTREAM=sentry.eventstream.kafka.KafkaEventStream`."
                )
            daemons += [_get_daemon("metrics")]

    if settings.SENTRY_USE_RELAY:
        daemons += [_get_daemon("ingest")]

    if needs_https and has_https:
        https_port = str(parsed_url.port)
        https_host = parsed_url.hostname

        # Determine a random port for the backend http server
        import socket

        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        s.bind((host, 0))
        port = s.getsockname()[1]
        s.close()
        bind = "%s:%d" % (host, port)

        daemons += [("https", [
            "https", "-host", https_host, "-listen", host + ":" + https_port,
            bind
        ])]

    from sentry.runner.commands.devservices import _prepare_containers

    for name, container_options in _prepare_containers("sentry",
                                                       silent=True).items():
        if container_options.get("with_devserver", False):
            daemons += [(name,
                         ["sentry", "devservices", "attach", "--fast", name])]

    # A better log-format for local dev when running through honcho,
    # but if there aren't any other daemons, we don't want to override.
    if daemons:
        uwsgi_overrides[
            "log-format"] = "%(method) %(status) %(uri) %(proto) %(size)"
    else:
        uwsgi_overrides[
            "log-format"] = "[%(ltime)] %(method) %(status) %(uri) %(proto) %(size)"

    server = SentryHTTPServer(host=host,
                              port=port,
                              workers=1,
                              extra_options=uwsgi_overrides,
                              debug=debug_server)

    # If we don't need any other daemons, just launch a normal uwsgi webserver
    # and avoid dealing with subprocesses
    if not daemons:
        return server.run()

    import sys
    from subprocess import list2cmdline

    from honcho.manager import Manager
    from honcho.printer import Printer

    os.environ["PYTHONUNBUFFERED"] = "true"

    if debug_server:
        threading.Thread(target=server.run).start()
    else:
        # Make sure that the environment is prepared before honcho takes over
        # This sets all the appropriate uwsgi env vars, etc
        server.prepare_environment()
        daemons += [_get_daemon("server")]

    if styleguide:
        daemons += [_get_daemon("storybook")]

    cwd = os.path.realpath(
        os.path.join(settings.PROJECT_ROOT, os.pardir, os.pardir))

    honcho_printer = Printer(prefix=prefix)

    if pretty:
        from sentry.runner.formatting import monkeypatch_honcho_write

        honcho_printer.write = types.MethodType(monkeypatch_honcho_write,
                                                honcho_printer)

    manager = Manager(honcho_printer)
    for name, cmd in daemons:
        manager.add_process(name, list2cmdline(cmd), quiet=False, cwd=cwd)

    manager.loop()
    sys.exit(manager.returncode)
Ejemplo n.º 24
0
 def test_write_with_set_width(self):
     out = FakeOutput()
     p = Printer(output=out, width=6)
     p.write(fake_message("giraffe\n"))
     self.assertEqual("12:42:00        | giraffe\n", out.string())
Ejemplo n.º 25
0
 def test_write_without_prefix_non_tty(self):
     out = FakeOutput()
     p = Printer(output=out, prefix=False)
     p.write(fake_message("paranoid android\n", name="foo", colour="31"))
     assert out.string() == "paranoid android\n"
Ejemplo n.º 26
0
 def test_write_with_name_and_set_width(self):
     out = FakeOutput()
     p = Printer(output=out, width=6)
     p.write(fake_message("narcissist\n", name="oop"))
     self.assertEqual("12:42:00 oop    | narcissist\n", out.string())
Ejemplo n.º 27
0
 def test_write_wrong_type(self):
     out = FakeOutput()
     p = Printer(output=out)
     with pytest.raises(RuntimeError):
         p.write(fake_message("monkeys\n", type="error"))
Ejemplo n.º 28
0
 def test_write_with_colour(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message("conflate\n", name="foo", colour="31"))
     self.assertEqual("\033[31m12:42:00 foo | \033[0mconflate\n",
                      out.string())
Ejemplo n.º 29
0
 def test_defaults_simple(self):
     out = FakeOutput()
     p = Printer(output=out, env=FakeEnv())
     p.write("monkeys")
     self.assertEqual("12:42:00 unknown | monkeys", out.last_write())
Ejemplo n.º 30
0
 def test_write_invalid_utf8(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message(b"\xfe\xff\n"))
     self.assertEqual("12:42:00 | \ufffd\ufffd\n", out.string())
Ejemplo n.º 31
0
 def test_name_simple(self):
     out = FakeOutput()
     p = Printer(output=out, name="Robert Louis Stevenson", env=FakeEnv())
     p.write("quiescent")
     self.assertEqual("12:42:00 Robert Louis Stevenson | quiescent",
                      out.last_write())
Ejemplo n.º 32
0
 def test_write_no_newline(self):
     out = FakeOutput()
     p = Printer(output=out)
     p.write(fake_message("monkeys"))
     self.assertEqual("12:42:00 | monkeys\n", out.string())
Ejemplo n.º 33
0
 def test_colour_simple(self):
     out = FakeOutput()
     p = Printer(output=out, name="red", colour="31", env=FakeEnv())
     p.write("conflate")
     self.assertEqual("\033[31m12:42:00 red | \033[0mconflate",
                      out.last_write())
Ejemplo n.º 34
0
 def test_write_flushes_output(self):
     out = FakeOutput()
     p = Printer(output=out, prefix=False)
     p.write(fake_message("paranoid android\n"))
     assert out.flushcount == 1