From dd982c5ace8e74467a972b140f0b4c5db0c89012 Mon Sep 17 00:00:00 2001 From: Alek Petuskey Date: Wed, 8 Nov 2023 17:41:08 -0800 Subject: [PATCH] Add benchmarking tests (#2143) --- .../{lighthouse.yml => benchmarks.yml} | 14 +- integration/benchmarks/benchmarks.py | 138 ++++++++++++++++ integration/benchmarks/helpers.py | 49 ++++++ .../benchmarks/test_compile_benchmark.py | 121 ++++++++++++++ poetry.lock | 155 +++++++++++++++++- pyproject.toml | 1 + scripts/benchmarks.sh | 77 +++++++++ scripts/lighthouse.sh | 123 -------------- 8 files changed, 545 insertions(+), 133 deletions(-) rename .github/workflows/{lighthouse.yml => benchmarks.yml} (79%) create mode 100644 integration/benchmarks/benchmarks.py create mode 100644 integration/benchmarks/helpers.py create mode 100644 integration/benchmarks/test_compile_benchmark.py create mode 100644 scripts/benchmarks.sh delete mode 100644 scripts/lighthouse.sh diff --git a/.github/workflows/lighthouse.yml b/.github/workflows/benchmarks.yml similarity index 79% rename from .github/workflows/lighthouse.yml rename to .github/workflows/benchmarks.yml index 706d7a30f..2b8037960 100644 --- a/.github/workflows/lighthouse.yml +++ b/.github/workflows/benchmarks.yml @@ -1,4 +1,4 @@ -name: lighthouse-tests +name: benchmarking on: push: @@ -62,8 +62,14 @@ jobs: run: | # Check that npm is home npm -v - poetry run bash scripts/lighthouse.sh ./reflex-web prod + poetry run bash scripts/benchmarks.sh ./reflex-web prod env: LHCI_GITHUB_APP_TOKEN: $ - POSTHOG: $ - \ No newline at end of file + - name: Run Benchmarks + working-directory: ./integration/benchmarks + run: + poetry run python benchmarks.py "$GITHUB_SHA" .lighthouseci + env: + GITHUB_SHA: ${{ github.sha }} + DATABASE_URL: ${{ secrets.DATABASE_URL }} + PR_TITLE: ${{ github.event.pull_request.title }} \ No newline at end of file diff --git a/integration/benchmarks/benchmarks.py b/integration/benchmarks/benchmarks.py new file mode 100644 index 000000000..787e95970 --- /dev/null +++ b/integration/benchmarks/benchmarks.py @@ -0,0 +1,138 @@ +"""Runs the benchmarks and inserts the results into the database.""" + +import json +import os +import sys + +import pytest +from helpers import insert_benchmarking_data + + +def get_lighthouse_scores(directory_path: str) -> dict: + """Extracts the Lighthouse scores from the JSON files in the specified directory. + + Args: + directory_path (str): The path to the directory containing the JSON files. + + Returns: + dict: The Lighthouse scores. + """ + scores = {} + + try: + for filename in os.listdir(directory_path): + if filename.endswith(".json") and filename != "manifest.json": + file_path = os.path.join(directory_path, filename) + with open(file_path, "r") as file: + data = json.load(file) + # Extract scores and add them to the dictionary with the filename as key + scores[data["finalUrl"].replace("http://localhost:3000/", "")] = { + "performance_score": data["categories"]["performance"]["score"], + "accessibility_score": data["categories"]["accessibility"][ + "score" + ], + "best_practices_score": data["categories"]["best-practices"][ + "score" + ], + "seo_score": data["categories"]["seo"]["score"], + "pwa_score": data["categories"]["pwa"]["score"], + } + except Exception as e: + print(e) + return {"error": "Error parsing JSON files"} + + return scores + + +def run_pytest_and_get_results(test_path=None) -> dict: + """Runs pytest and returns the results. + + Args: + test_path: The path to the tests to run. + + Returns: + dict: The results of the tests. + """ + # Set the default path to the current directory if no path is provided + if not test_path: + test_path = os.getcwd() + # Ensure you have installed the pytest-json plugin before running this + pytest_args = ["-v", "--benchmark-json=benchmark_report.json", test_path] + + # Run pytest with the specified arguments + pytest.main(pytest_args) + + # Print ls of the current directory + print(os.listdir()) + + with open("benchmark_report.json", "r") as file: + pytest_results = json.load(file) + + return pytest_results + + +def extract_stats_from_json(json_data) -> list[dict]: + """Extracts the stats from the JSON data and returns them as a list of dictionaries. + + Args: + json_data: The JSON data to extract the stats from. + + Returns: + list[dict]: The stats for each test. + """ + # Load the JSON data if it is a string, otherwise assume it's already a dictionary + data = json.loads(json_data) if isinstance(json_data, str) else json_data + + # Initialize an empty list to store the stats for each test + test_stats = [] + + # Iterate over each test in the 'benchmarks' list + for test in data.get("benchmarks", []): + stats = test.get("stats", {}) + test_name = test.get("name", "Unknown Test") + min_value = stats.get("min", None) + max_value = stats.get("max", None) + mean_value = stats.get("mean", None) + stdev_value = stats.get("stddev", None) + + test_stats.append( + { + "test_name": test_name, + "min": min_value, + "max": max_value, + "mean": mean_value, + "stdev": stdev_value, + } + ) + + return test_stats + + +def main(): + """Runs the benchmarks and inserts the results into the database.""" + # Get the commit SHA and JSON directory from the command line arguments + commit_sha = sys.argv[1] + json_dir = sys.argv[2] + + # Get the PR title and database URL from the environment variables + pr_title = os.environ.get("PR_TITLE") + db_url = os.environ.get("DATABASE_URL") + + if db_url is None or pr_title is None: + sys.exit("Missing environment variables") + + # Run pytest and get the results + results = run_pytest_and_get_results() + cleaned_results = extract_stats_from_json(results) + + # Get the Lighthouse scores + lighthouse_scores = get_lighthouse_scores(json_dir) + + # Insert the data into the database + insert_benchmarking_data( + db_url, lighthouse_scores, cleaned_results, commit_sha, pr_title + ) + + +if __name__ == "__main__": + main() diff --git a/integration/benchmarks/helpers.py b/integration/benchmarks/helpers.py new file mode 100644 index 000000000..e1a3f493b --- /dev/null +++ b/integration/benchmarks/helpers.py @@ -0,0 +1,49 @@ +"""Helper functions for the benchmarking integration.""" + +import json +from datetime import datetime + +import psycopg2 + + +def insert_benchmarking_data( + db_connection_url: str, + lighthouse_data: dict, + performance_data: list[dict], + commit_sha: str, + pr_title: str, +): + """Insert the benchmarking data into the database. + + Args: + db_connection_url: The URL to connect to the database. + lighthouse_data: The Lighthouse data to insert. + performance_data: The performance data to insert. + commit_sha: The commit SHA to insert. + pr_title: The PR title to insert. + """ + # Serialize the JSON data + lighthouse_json = json.dumps(lighthouse_data) + performance_json = json.dumps(performance_data) + + # Get the current timestamp + current_timestamp = datetime.now() + + # Connect to the database and insert the data + with psycopg2.connect(db_connection_url) as conn, conn.cursor() as cursor: + insert_query = """ + INSERT INTO benchmarks (lighthouse, performance, commit_sha, pr_title, time) + VALUES (%s, %s, %s, %s, %s); + """ + cursor.execute( + insert_query, + ( + lighthouse_json, + performance_json, + commit_sha, + pr_title, + current_timestamp, + ), + ) + # Commit the transaction + conn.commit() diff --git a/integration/benchmarks/test_compile_benchmark.py b/integration/benchmarks/test_compile_benchmark.py new file mode 100644 index 000000000..82162de00 --- /dev/null +++ b/integration/benchmarks/test_compile_benchmark.py @@ -0,0 +1,121 @@ +"""Benchmark the time it takes to compile a reflex app.""" + +import importlib + +import reflex + +rx = reflex + + +class State(rx.State): + """A simple state class with a count variable.""" + + count: int = 0 + + def increment(self): + """Increment the count.""" + self.count += 1 + + def decrement(self): + """Decrement the count.""" + self.count -= 1 + + +class SliderVariation(State): + """A simple state class with a count variable.""" + + value: int = 50 + + def set_end(self, value: int): + """Increment the count. + + Args: + value: The value of the slider. + """ + self.value = value + + +def sample_small_page() -> rx.Component: + """A simple page with a button that increments the count. + + Returns: + A reflex component. + """ + return rx.vstack( + *[rx.button(State.count, font_size="2em") for i in range(100)], + spacing="1em", + ) + + +def sample_large_page() -> rx.Component: + """A large page with a slider that increments the count. + + Returns: + A reflex component. + """ + return rx.vstack( + *[ + rx.vstack( + rx.heading(SliderVariation.value), + rx.slider(on_change_end=SliderVariation.set_end), + width="100%", + ) + for i in range(100) + ], + spacing="1em", + ) + + +def add_small_pages(app: rx.App): + """Add 10 small pages to the app. + + Args: + app: The reflex app to add the pages to. + """ + for i in range(10): + app.add_page(sample_small_page, route=f"/{i}") + + +def add_large_pages(app: rx.App): + """Add 10 large pages to the app. + + Args: + app: The reflex app to add the pages to. + """ + for i in range(10): + app.add_page(sample_large_page, route=f"/{i}") + + +def test_mean_import_time(benchmark): + """Test that the mean import time is less than 1 second. + + Args: + benchmark: The benchmark fixture. + """ + + def import_reflex(): + importlib.reload(reflex) + + # Benchmark the import + benchmark(import_reflex) + + +def test_mean_add_small_page_time(benchmark): + """Test that the mean add page time is less than 1 second. + + Args: + benchmark: The benchmark fixture. + """ + app = rx.App(state=State) + benchmark(add_small_pages, app) + + +def test_mean_add_large_page_time(benchmark): + """Test that the mean add page time is less than 1 second. + + Args: + benchmark: The benchmark fixture. + """ + app = rx.App(state=State) + results = benchmark(add_large_pages, app) + print(results) diff --git a/poetry.lock b/poetry.lock index 38b23f1d4..d06ad9060 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,9 +1,10 @@ -# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. +# This file is automatically @generated by Poetry and should not be changed by hand. [[package]] name = "alembic" version = "1.12.1" description = "A database migration tool for SQLAlchemy." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -25,6 +26,7 @@ tz = ["python-dateutil"] name = "anyio" version = "4.0.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -46,6 +48,7 @@ trio = ["trio (>=0.22)"] name = "async-timeout" version = "4.0.3" description = "Timeout context manager for asyncio programs" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -57,6 +60,7 @@ files = [ name = "asynctest" version = "0.13.0" description = "Enhance the standard unittest package with features for testing asyncio libraries" +category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -68,6 +72,7 @@ files = [ name = "attrs" version = "23.1.0" description = "Classes Without Boilerplate" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -86,6 +91,7 @@ tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pyte name = "bidict" version = "0.22.1" description = "The bidirectional mapping library for Python." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -102,6 +108,7 @@ test = ["hypothesis", "pytest", "pytest-benchmark[histogram]", "pytest-cov", "py name = "black" version = "22.12.0" description = "The uncompromising code formatter." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -137,6 +144,7 @@ uvloop = ["uvloop (>=0.15.2)"] name = "certifi" version = "2023.7.22" description = "Python package for providing Mozilla's CA Bundle." +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -148,6 +156,7 @@ files = [ name = "cffi" version = "1.16.0" description = "Foreign Function Interface for Python calling C code." +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -212,6 +221,7 @@ pycparser = "*" name = "cfgv" version = "3.4.0" description = "Validate configuration and produce human readable error messages." +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -223,6 +233,7 @@ files = [ name = "click" version = "8.1.7" description = "Composable command line interface toolkit" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -237,6 +248,7 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} name = "cloudpickle" version = "2.2.1" description = "Extended pickling support for Python objects" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -248,6 +260,7 @@ files = [ name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." +category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -259,6 +272,7 @@ files = [ name = "coverage" version = "7.3.2" description = "Code coverage measurement for Python" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -326,6 +340,7 @@ toml = ["tomli"] name = "darglint" version = "1.8.1" description = "A utility for ensuring Google-style docstrings stay up to date with the source code." +category = "dev" optional = false python-versions = ">=3.6,<4.0" files = [ @@ -337,6 +352,7 @@ files = [ name = "distlib" version = "0.3.7" description = "Distribution utilities" +category = "dev" optional = false python-versions = "*" files = [ @@ -348,6 +364,7 @@ files = [ name = "distro" version = "1.8.0" description = "Distro - an OS platform information API" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -359,6 +376,7 @@ files = [ name = "exceptiongroup" version = "1.1.3" description = "Backport of PEP 654 (exception groups)" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -373,6 +391,7 @@ test = ["pytest (>=6)"] name = "fastapi" version = "0.96.1" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -394,6 +413,7 @@ test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==23.1.0)", "coverage[toml] (>=6 name = "filelock" version = "3.13.1" description = "A platform independent file lock." +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -410,6 +430,7 @@ typing = ["typing-extensions (>=4.8)"] name = "greenlet" version = "3.0.1" description = "Lightweight in-process concurrent programming" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -480,6 +501,7 @@ test = ["objgraph", "psutil"] name = "gunicorn" version = "20.1.0" description = "WSGI HTTP Server for UNIX" +category = "main" optional = false python-versions = ">=3.5" files = [ @@ -500,6 +522,7 @@ tornado = ["tornado (>=0.2)"] name = "h11" version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -511,6 +534,7 @@ files = [ name = "httpcore" version = "0.17.3" description = "A minimal low-level HTTP client." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -522,16 +546,17 @@ files = [ anyio = ">=3.0,<5.0" certifi = "*" h11 = ">=0.13,<0.15" -sniffio = "==1.*" +sniffio = ">=1.0.0,<2.0.0" [package.extras] http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] +socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "httpx" version = "0.24.1" description = "The next generation HTTP client." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -547,14 +572,15 @@ sniffio = "*" [package.extras] brotli = ["brotli", "brotlicffi"] -cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] +socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "identify" version = "2.5.31" description = "File identification library for Python" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -569,6 +595,7 @@ license = ["ukkonen"] name = "idna" version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" optional = false python-versions = ">=3.5" files = [ @@ -580,6 +607,7 @@ files = [ name = "importlib-metadata" version = "6.8.0" description = "Read metadata from Python packages" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -599,6 +627,7 @@ testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs name = "importlib-resources" version = "6.1.0" description = "Read resources from Python packages" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -617,6 +646,7 @@ testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -628,6 +658,7 @@ files = [ name = "jinja2" version = "3.1.2" description = "A very fast and expressive template engine." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -645,6 +676,7 @@ i18n = ["Babel (>=2.7)"] name = "mako" version = "1.2.4" description = "A super-fast templating language that borrows the best ideas from the existing templating languages." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -664,6 +696,7 @@ testing = ["pytest"] name = "markdown-it-py" version = "3.0.0" description = "Python port of markdown-it. Markdown parsing, done right!" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -688,6 +721,7 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] name = "markupsafe" version = "2.1.3" description = "Safely add untrusted strings to HTML/XML markup." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -747,6 +781,7 @@ files = [ name = "mdurl" version = "0.1.2" description = "Markdown URL utilities" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -758,6 +793,7 @@ files = [ name = "mypy-extensions" version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." +category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -769,6 +805,7 @@ files = [ name = "nodeenv" version = "1.8.0" description = "Node.js virtual environment builder" +category = "dev" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" files = [ @@ -783,6 +820,7 @@ setuptools = "*" name = "numpy" version = "1.24.4" description = "Fundamental package for array computing in Python" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -820,6 +858,7 @@ files = [ name = "numpy" version = "1.26.1" description = "Fundamental package for array computing in Python" +category = "dev" optional = false python-versions = "<3.13,>=3.9" files = [ @@ -861,6 +900,7 @@ files = [ name = "outcome" version = "1.3.0.post0" description = "Capture the outcome of Python function calls." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -875,6 +915,7 @@ attrs = ">=19.2.0" name = "packaging" version = "23.2" description = "Core utilities for Python packages" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -886,6 +927,7 @@ files = [ name = "pandas" version = "1.5.3" description = "Powerful data structures for data analysis, time series, and statistics" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -930,6 +972,7 @@ test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"] name = "pandas" version = "2.1.2" description = "Powerful data structures for data analysis, time series, and statistics" +category = "dev" optional = false python-versions = ">=3.9" files = [ @@ -998,6 +1041,7 @@ xml = ["lxml (>=4.8.0)"] name = "pathspec" version = "0.11.2" description = "Utility library for gitignore style pattern matching of file paths." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1009,6 +1053,7 @@ files = [ name = "pillow" version = "10.1.0" description = "Python Imaging Library (Fork)" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1076,6 +1121,7 @@ tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "pa name = "pipdeptree" version = "2.13.0" description = "Command line utility to show dependency tree of packages." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1091,6 +1137,7 @@ test = ["covdefaults (>=2.3)", "diff-cover (>=7.7)", "pip (>=23.2)", "pytest (>= name = "platformdirs" version = "3.11.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1106,6 +1153,7 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-co name = "plotly" version = "5.18.0" description = "An open-source, interactive data visualization library for Python" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1121,6 +1169,7 @@ tenacity = ">=6.2.0" name = "pluggy" version = "1.3.0" description = "plugin and hook calling mechanisms for python" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1136,6 +1185,7 @@ testing = ["pytest", "pytest-benchmark"] name = "pre-commit" version = "3.5.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1154,6 +1204,7 @@ virtualenv = ">=20.10.0" name = "psutil" version = "5.9.6" description = "Cross-platform lib for process and system monitoring in Python." +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ @@ -1178,10 +1229,23 @@ files = [ [package.extras] test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] +[[package]] +name = "py-cpuinfo" +version = "9.0.0" +description = "Get CPU info with pure Python" +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690"}, + {file = "py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5"}, +] + [[package]] name = "pycparser" version = "2.21" description = "C parser in Python" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -1193,6 +1257,7 @@ files = [ name = "pydantic" version = "1.10.13" description = "Data validation and settings management using python type hints" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1245,6 +1310,7 @@ email = ["email-validator (>=1.0.3)"] name = "pygments" version = "2.16.1" description = "Pygments is a syntax highlighting package written in Python." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1259,6 +1325,7 @@ plugins = ["importlib-metadata"] name = "pyright" version = "1.1.334" description = "Command line wrapper for pyright" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1277,6 +1344,7 @@ dev = ["twine (>=3.4.1)"] name = "pysocks" version = "1.7.1" description = "A Python SOCKS client module. See https://github.com/Anorov/PySocks for more information." +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -1289,6 +1357,7 @@ files = [ name = "pytest" version = "7.4.3" description = "pytest: simple powerful testing with Python" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1311,6 +1380,7 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no name = "pytest-asyncio" version = "0.20.3" description = "Pytest support for asyncio" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1325,10 +1395,32 @@ pytest = ">=6.1.0" docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] +[[package]] +name = "pytest-benchmark" +version = "4.0.0" +description = "A ``pytest`` fixture for benchmarking code. It will group the tests into rounds that are calibrated to the chosen timer." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-benchmark-4.0.0.tar.gz", hash = "sha256:fb0785b83efe599a6a956361c0691ae1dbb5318018561af10f3e915caa0048d1"}, + {file = "pytest_benchmark-4.0.0-py3-none-any.whl", hash = "sha256:fdb7db64e31c8b277dff9850d2a2556d8b60bcb0ea6524e36e28ffd7c87f71d6"}, +] + +[package.dependencies] +py-cpuinfo = "*" +pytest = ">=3.8" + +[package.extras] +aspect = ["aspectlib"] +elasticsearch = ["elasticsearch"] +histogram = ["pygal", "pygaljs"] + [[package]] name = "pytest-cov" version = "4.1.0" description = "Pytest plugin for measuring coverage." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1347,6 +1439,7 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale name = "pytest-mock" version = "3.12.0" description = "Thin-wrapper around the mock package for easier use with pytest" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1364,6 +1457,7 @@ dev = ["pre-commit", "pytest-asyncio", "tox"] name = "python-dateutil" version = "2.8.2" description = "Extensions to the standard Python datetime module" +category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ @@ -1378,6 +1472,7 @@ six = ">=1.5" name = "python-engineio" version = "4.8.0" description = "Engine.IO server and client for Python" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1397,6 +1492,7 @@ docs = ["sphinx"] name = "python-multipart" version = "0.0.5" description = "A streaming multipart parser for Python" +category = "main" optional = false python-versions = "*" files = [ @@ -1410,6 +1506,7 @@ six = ">=1.4.0" name = "python-socketio" version = "5.10.0" description = "Socket.IO server and client for Python" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1430,6 +1527,7 @@ docs = ["sphinx"] name = "pytz" version = "2023.3.post1" description = "World timezone definitions, modern and historical" +category = "dev" optional = false python-versions = "*" files = [ @@ -1441,6 +1539,7 @@ files = [ name = "pyyaml" version = "6.0.1" description = "YAML parser and emitter for Python" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1449,6 +1548,7 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -1456,8 +1556,15 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -1474,6 +1581,7 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -1481,6 +1589,7 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -1490,6 +1599,7 @@ files = [ name = "redis" version = "4.6.0" description = "Python client for Redis database and key-value store" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1508,6 +1618,7 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)" name = "rich" version = "13.6.0" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +category = "main" optional = false python-versions = ">=3.7.0" files = [ @@ -1527,6 +1638,7 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] name = "ruff" version = "0.0.244" description = "An extremely fast Python linter, written in Rust." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1552,6 +1664,7 @@ files = [ name = "selenium" version = "4.15.2" description = "" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1569,6 +1682,7 @@ urllib3 = {version = ">=1.26,<3", extras = ["socks"]} name = "setuptools" version = "68.2.2" description = "Easily download, build, install, upgrade, and uninstall Python packages" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1585,6 +1699,7 @@ testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jar name = "simple-websocket" version = "1.0.0" description = "Simple WebSocket server and client for Python" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1602,6 +1717,7 @@ docs = ["sphinx"] name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -1613,6 +1729,7 @@ files = [ name = "sniffio" version = "1.3.0" description = "Sniff out which async library your code is running under" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1624,6 +1741,7 @@ files = [ name = "sortedcontainers" version = "2.4.0" description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" +category = "dev" optional = false python-versions = "*" files = [ @@ -1635,6 +1753,7 @@ files = [ name = "sqlalchemy" version = "1.4.41" description = "Database Abstraction Library" +category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ @@ -1709,6 +1828,7 @@ sqlcipher = ["sqlcipher3-binary"] name = "sqlalchemy2-stubs" version = "0.0.2a36" description = "Typing Stubs for SQLAlchemy 1.4" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1723,6 +1843,7 @@ typing-extensions = ">=3.7.4" name = "sqlmodel" version = "0.0.8" description = "SQLModel, SQL databases in Python, designed for simplicity, compatibility, and robustness." +category = "main" optional = false python-versions = ">=3.6.1,<4.0.0" files = [ @@ -1739,6 +1860,7 @@ sqlalchemy2-stubs = "*" name = "starlette" version = "0.27.0" description = "The little ASGI library that shines." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1757,6 +1879,7 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyam name = "starlette-admin" version = "0.9.0" description = "Fast, beautiful and extensible administrative interface framework for Starlette/FastApi applications" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1779,6 +1902,7 @@ test = ["aiomysql (>=0.1.1,<0.2.0)", "aiosqlite (>=0.17.0,<0.20.0)", "arrow (>=1 name = "tabulate" version = "0.9.0" description = "Pretty-print tabular data" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1793,6 +1917,7 @@ widechars = ["wcwidth"] name = "tenacity" version = "8.2.3" description = "Retry code until it succeeds" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1807,6 +1932,7 @@ doc = ["reno", "sphinx", "tornado (>=4.5)"] name = "toml" version = "0.10.2" description = "Python Library for Tom's Obvious, Minimal Language" +category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -1818,6 +1944,7 @@ files = [ name = "tomli" version = "2.0.1" description = "A lil' TOML parser" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1829,6 +1956,7 @@ files = [ name = "trio" version = "0.23.1" description = "A friendly Python library for async concurrency and I/O" +category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1849,6 +1977,7 @@ sortedcontainers = "*" name = "trio-websocket" version = "0.11.1" description = "WebSocket library for Trio" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1865,6 +1994,7 @@ wsproto = ">=0.14" name = "typer" version = "0.9.0" description = "Typer, build great CLIs. Easy to code. Based on Python type hints." +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1886,6 +2016,7 @@ test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6. name = "types-tabulate" version = "0.9.0.3" description = "Typing stubs for tabulate" +category = "dev" optional = false python-versions = "*" files = [ @@ -1897,6 +2028,7 @@ files = [ name = "typing-extensions" version = "4.8.0" description = "Backported and Experimental Type Hints for Python 3.8+" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1908,6 +2040,7 @@ files = [ name = "tzdata" version = "2023.3" description = "Provider of IANA time zone data" +category = "dev" optional = false python-versions = ">=2" files = [ @@ -1919,6 +2052,7 @@ files = [ name = "urllib3" version = "2.0.7" description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1939,6 +2073,7 @@ zstd = ["zstandard (>=0.18.0)"] name = "uvicorn" version = "0.20.0" description = "The lightning-fast ASGI server." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1957,6 +2092,7 @@ standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", name = "uvicorn" version = "0.24.0" description = "The lightning-fast ASGI server." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1975,6 +2111,7 @@ standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", name = "virtualenv" version = "20.24.6" description = "Virtual Python Environment builder" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1995,6 +2132,7 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess name = "watchdog" version = "2.3.1" description = "Filesystem events monitoring" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -2035,6 +2173,7 @@ watchmedo = ["PyYAML (>=3.10)"] name = "watchfiles" version = "0.19.0" description = "Simple, modern and high performance file watching and code reload in python." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2069,6 +2208,7 @@ anyio = ">=3.0.0" name = "websockets" version = "10.4" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2147,6 +2287,7 @@ files = [ name = "wrapt" version = "1.15.0" description = "Module for decorators, wrappers and monkey patching." +category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" files = [ @@ -2231,6 +2372,7 @@ files = [ name = "wsproto" version = "1.2.0" description = "WebSockets state-machine based protocol implementation" +category = "main" optional = false python-versions = ">=3.7.0" files = [ @@ -2245,6 +2387,7 @@ h11 = ">=0.9.0,<1" name = "zipp" version = "3.17.0" description = "Backport of pathlib-compatible object wrapper for zip files" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2259,4 +2402,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "5b1490dc4da1ddebdf65472535949c8d51fb81f10e26861ea35bbddb1afca004" +content-hash = "d5765fcff519e4d18744355420f7ec03a9821c99ed96421c016276ac0bb938e0" diff --git a/pyproject.toml b/pyproject.toml index a7ec86d0a..30d2734f0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -82,6 +82,7 @@ asynctest = "^0.13.0" pre-commit = {version = "^3.2.1", python = ">=3.8,<4.0"} selenium = "^4.11.0" types-tabulate = "^0.9.0.3" +pytest-benchmark = "^4.0.0" [tool.poetry.scripts] reflex = "reflex.reflex:cli" diff --git a/scripts/benchmarks.sh b/scripts/benchmarks.sh new file mode 100644 index 000000000..dcd3f14f9 --- /dev/null +++ b/scripts/benchmarks.sh @@ -0,0 +1,77 @@ +#!/bin/bash + +# Change directory to the first argument passed to the script +project_dir=$1 +shift +pushd "$project_dir" || exit 1 +echo "Changed directory to $project_dir" + + +# So we get stdout / stderr from Python ASAP. Without this, delays can be very long (e.g. on Windows, Github Actions) +export PYTHONUNBUFFERED=1 + +env_mode=$1 +shift +check_ports=${1:-3000 8000} +shift + +# Start the server in the background +export TELEMETRY_ENABLED=false +reflex run --env "$env_mode" "$@" & pid=$! + +# Within the context of this bash, $pid_in_bash is what we need to pass to "kill" on exit +# This is true on all platforms. +pid_in_bash=$pid +trap "kill -INT $pid_in_bash ||:" EXIT + +echo "Started server with PID $pid" + +# Assume we run from the root of the repo +popd + +# In Windows, our Python script below needs to work with the WINPID +if [ -f /proc/$pid/winpid ]; then + pid=$(cat /proc/$pid/winpid) + echo "Windows detected, passing winpid $pid to port waiter" +fi + +python scripts/wait_for_listening_port.py $check_ports --timeout=600 --server-pid "$pid" + + +# Check if something is running on port 3000 +if curl --output /dev/null --silent --head --fail "http://localhost:3000"; then + echo "URL exists: http://localhost:3000" +else + echo "URL does not exist: https://localhost:3000" +fi + +mkdir -p ./tests/benchmarks/.lighthouseci + +# Create a lighthouserc.js file +cat << EOF > lighthouserc.js +module.exports = { + ci: { + collect: { + isSinglePageApplication: true, + numberOfRuns: 1, + url: ['http://localhost:3000', "http://localhost:3000/docs/getting-started/introduction/", "http://localhost:3000/blog/2023-08-02-seed-annoucement/"] + }, + upload: { + target: 'filesystem', + "outputDir": "./integration/benchmarks/.lighthouseci" + }, + }, +}; +EOF + +# Install and Run LHCI +npm install -g @lhci/cli +lhci autorun + +# Check to see if the LHCI report is generated +if [ -d "./integration/benchmarks/.lighthouseci" ] && [ "$(ls -A ./integration/benchmarks/.lighthouseci)" ]; then + echo "LHCI report generated" +else + echo "LHCI report not generated" + exit 1 # Exits the script with a status of 1, which will cause the GitHub Action to stop +fi \ No newline at end of file diff --git a/scripts/lighthouse.sh b/scripts/lighthouse.sh deleted file mode 100644 index 741a8512c..000000000 --- a/scripts/lighthouse.sh +++ /dev/null @@ -1,123 +0,0 @@ -#!/bin/bash - -# Change directory to the first argument passed to the script -project_dir=$1 -shift -pushd "$project_dir" || exit 1 -echo "Changed directory to $project_dir" - - -# So we get stdout / stderr from Python ASAP. Without this, delays can be very long (e.g. on Windows, Github Actions) -export PYTHONUNBUFFERED=1 - -env_mode=$1 -shift -check_ports=${1:-3000 8000} -shift - -# Start the server in the background -export TELEMETRY_ENABLED=false -reflex run --loglevel debug --env "$env_mode" "$@" & pid=$! - -# Within the context of this bash, $pid_in_bash is what we need to pass to "kill" on exit -# This is true on all platforms. -pid_in_bash=$pid -trap "kill -INT $pid_in_bash ||:" EXIT - -echo "Started server with PID $pid" - -# Assume we run from the root of the repo -popd - -# In Windows, our Python script below needs to work with the WINPID -if [ -f /proc/$pid/winpid ]; then - pid=$(cat /proc/$pid/winpid) - echo "Windows detected, passing winpid $pid to port waiter" -fi - -python scripts/wait_for_listening_port.py $check_ports --timeout=600 --server-pid "$pid" - - -# Check if something is running on port 3000 -if curl --output /dev/null --silent --head --fail "http://localhost:3000"; then - echo "URL exists: http://localhost:3000" -else - echo "URL does not exist: https://localhost:3000" -fi - -# Change to .web directory -project_dir=$1 -shift -pushd "$project_dir" || exit 1 -echo "Changed directory to $project_dir" -cd .web - -# Create a lighthouserc.js file -cat << EOF > lighthouserc.js -module.exports = { - ci: { - collect: { - isSinglePageApplication: true, - numberOfRuns: 1, - url: ['http://localhost:3000', "http://localhost:3000/docs/getting-started/introduction/", "http://localhost:3000/blog/2023-08-02-seed-annoucement/"] - }, - upload: { - target: 'temporary-public-storage', - }, - }, -}; -EOF - -# Install and Run LHCI -npm install -g @lhci/cli -lhci autorun || echo "LHCI failed!" - -#!/bin/bash - -# Define the base URL where you want to send the POST requests -base_url="https://app.posthog.com/capture/" - -# Directory containing JSON files -json_dir=".lighthouseci" - -# API Key -api_key="$POSTHOG" - -# Get the current timestamp -timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ") - -# Loop through each JSON file in the directory -for json_file in "$json_dir"/*.json; do - if [ -f "$json_file" ]; then - # Extract the file name without the extension - file_name=$(basename "$json_file" .json) - - # Generate a random distinct_id (a random number) - distinct_id=$((RANDOM)) - - # Read the contents of the JSON file - json_data=$(cat "$json_file") - - # Construct the event name with the JSON file name - event="Lighthouse CI - $file_name" - - # Construct the JSON payload with the random distinct_id - payload="{\"api_key\": \"$api_key\", \"event\": \"$event\", \"timestamp\": \"$timestamp\", \"distinct_id\": $distinct_id, \"properties\": $json_data}" - - # Create a temporary file for the payload - tmpfile=$(mktemp) - - # Write the payload to the temporary file - echo "$payload" > "$tmpfile" - - # Send the POST request with the constructed payload using curl - response=$(curl -X POST -H "Content-Type: application/json" --data @"$tmpfile" "$base_url") - - # Clean up the temporary file - rm "$tmpfile" - - # Print the response for each file - echo "Response for $json_file:" - echo "$response" - fi -done \ No newline at end of file