Repository navigation
test: share integration session, use spark.master=local, and align CI extras - #205
Conversation
There was a problem hiding this comment.
Code Review
This pull request refactors the integration test suite for ManagedSparkSession, including significant cleanup of fixtures and test logic to improve test isolation and reliability. The changes include centralizing session state management in conftest.py, removing redundant test code, and updating tests to handle session lifecycle and cleanup more robustly. My review identified potential test isolation issues related to PySpark's global session state and unnecessary view creation in tests, which are addressed in the provided comments.
f4db69e to
957e041
Compare
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request refactors the integration test suite for ManagedSparkSession, improving test isolation, session lifecycle management, and cleanup logic. It also updates environment variable handling in fixtures and adds robust error handling for session termination. My feedback highlights a potential risk in the os_environment fixture regarding os.environ.clear() and suggests a safer approach to restoring environment variables, as well as a recommendation to wrap the test_serverless_session_termination_and_deletion_lifecycle test in a try...finally block to ensure reliable resource cleanup.
… extras - Add tests/integration/conftest.py to provide a session-scoped default multi-node ManagedSparkSession for non-destructive tests (SQL, UDFs, %%sparksql, %dpip) and an isolated_session_state fixture for lifecycle tests. - Configure isolated control-plane and session lifecycle tests with spark.master=local (single-node mode: 1 driver VM, 0 executor node pools) and 4-core executor overrides instead of 16-core executors. - Remove the unused image_version=[None, '3.0'] fixture that previously doubled the integration suite. - Set default safety TTLs (MANAGED_SPARK_CONNECT_TTL_SECONDS=1800, MANAGED_SPARK_CONNECT_IDLE_TTL_SECONDS=600) and default/short-name subnet normalization in conftest.py, and ensure named and lifecycle sessions are terminated in finally blocks so sessions are never leaked. - Consolidate termination and deletion lifecycle tests into test_serverless_session_termination_and_deletion_lifecycle, assert SessionTemplate default runtime version on the created Session, and remove pure local CLI/regex tests from tests/integration/ that are already covered in tests/unit/. - Together, these reduce remote Dataproc Serverless clusters per run from 42 to 5 (1 multi-node + 4 single-node), total GCE VMs from ~130 to 7 (-94.6%), and end-to-end runtime to ~8 minutes. - Move test_create_local_spark_session (DATAPROC_WORKLOAD_TYPE=batch) to tests/local/test_sparksql_local.py so it runs on every PR in the spark lane, and isolate local Spark Connect environment/proxy state. - Switch GitHub Actions workflows to astral-sh/setup-uv + uv pip install, update integration-tests.yaml to install .[client,interactive], and update tests.yaml to verify unit tests both without [interactive] and with [interactive].
957e041 to
b016565
Compare
Summary
Refactors the integration test suite and CI workflows to substantially reduce Dataproc Serverless session churn, VM footprint, and vulnerability to regional GCE stockouts (
503 Failed to create main node pool), while expanding CI coverage across packaging extras ([client],[spark], and with/without[interactive]) and switching CI dependency installation touv.ml-pipeline-session-*× 2 + terminated-recreate × 2)finally+ 10m idle TTL)494s)Key Changes
P0: Shared Session Fixture, Dead Parameterization Removal, and Leak Prevention
tests/integration/conftest.py): Provides a session-scoped default multi-nodeManagedSparkSession(_shared_connect_session/connect_session) shared across all non-destructive tests (test_create_spark_session_with_default_notebook_behavior,test_reuse_s8s_spark_session,test_sql_functions,test_sql_udf,test_sparksql_magic_with_managed_spark_session,test_dpip_install_success,test_dpip_install_failure), and anisolated_session_statefixture for tests that manage their own session lifecycle.image_version=[None, "3.0"]fixture: Previously parameterized every test intest_session.pyandtest_magics.pywithout ever passingimage_versionto the session builder, doubling the entire integration suite.MANAGED_SPARK_CONNECT_TTL_SECONDS=1800(30m) andMANAGED_SPARK_CONNECT_IDLE_TTL_SECONDS=600(10m, the minimum allowed byServerlessValidator) by default inconftest.py, and foldstest_stop_named_session_with_terminate_true+finally:cleanup intotest_session_reuse_with_custom_idso named sessions are never leaked for 24 hours.tests/integration/conftest.py): Falls back to"default"whenMANAGED_SPARK_CONNECT_SUBNETis unset or empty, and qualifies short subnetwork names (e.g."default","default-auto") toprojects/{test_project}/regions/{test_region}/subnetworks/{test_subnet}while passing already-qualifiedprojects/.../subnetworks/...URIs through unchanged.P1: Single-Node Mode (
spark.master=local) & Test Consolidationspark.master=localon isolated control-plane/lifecycle tests: Provisions a single 4-vCPU driver VM and 0 executor node pools fortest_create_spark_session_with_session_template_and_user_provided_session_config,test_session_reuse_with_custom_id, andtest_serverless_session_termination_and_deletion_lifecycle, while keeping the sharedconnect_sessionmulti-node to test out-of-the-box defaults, remote UDFs, and%dpipartifact distribution.SessionTemplatedefault version assertion: Changes.config("spark.executor.cores", "7") ... .config("spark.executor.cores", "16")to"8""4"withspark.master=local, and assertssession.runtime_config.version == ManagedSparkSession._DEFAULT_RUNTIME_VERSIONon the createdSession(fixing a precedence bug in the oldassert ... == ... if image_version is None else image_versionexpression, which previously evaluatedassert "3.0"becauseCreateSessionTemplateleavessession_template.runtime_config.versionempty until a session is instantiated).test_stop_managed_session_with_terminate_false,test_get_or_create_spark_session_with_terminated_serverless_session,test_stop_spark_session_with_terminated_serverless_session, andtest_stop_spark_session_with_deleted_serverless_sessionintotest_serverless_session_termination_and_deletion_lifecycle(2 single-node sessions instead of 4 multi-node sessions).tests/integration/: Removes pure local CLI/regex validation tests that are already covered intests/unit/.P2: Realistic CI Packaging Lanes &
uvDependency Installationuv(astral-sh/setup-uv): Replacespip installwithastral-sh/setup-uv+uv pip install --systemacrosstests.yaml,integration-tests.yaml,pyink.yaml, andlint-readme.yaml(with~/.cache/uvkeyed onsetup.pyandrequirements-test.txt), cutting dependency installation to ~2s for[client]and ~20s for[spark]..[client,interactive]inintegration-tests.yaml: Tests against the lightweightpyspark-client+pyspark-connectruntime recommended in the README and ensures%%sparksqlis not skipped in integration CI.[interactive]intests.yaml: Installs.[${{ matrix.spark-extra }}]first to runTestWithoutInteractiveExtra(expanded to testManagedSparkSession.builder.getOrCreate(),get_tqdm_bar(),_repr_html_(), andstop()whenIPython/sqlparse/traitlets/colabsqlviz/ipywidgetsare absent), then installs.[${{ matrix.spark-extra }},interactive]for the full unit and local suites.test_create_local_spark_sessionintests/local/test_sparksql_local.py: Moves theDATAPROC_WORKLOAD_TYPE=batchlocal classic Spark test intotests/local/so it runs on every PR in thesparklane under Java 17/21, and isolates local Spark Connect proxy/environment state.