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())
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")
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"
def test_write(self): out = FakeOutput() p = Printer(output=out) p.write(fake_message("monkeys\n")) assert out.string() == "12:42:00 | monkeys\n"
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"
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())
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())
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())
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"
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"
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"
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"
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())
def test_write_wrong_type(self): out = FakeOutput() p = Printer(output=out) with pytest.raises(RuntimeError): p.write(fake_message("monkeys\n", type="error"))
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())
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())
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())
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)
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())
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())
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())
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())
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