Skip to content

[BEAM-10527] Migrate Flink and Spark tests to pytest.#12385

Merged
mxm merged 2 commits intoapache:masterfrom
ibzib:BEAM-10527
Oct 1, 2020
Merged

[BEAM-10527] Migrate Flink and Spark tests to pytest.#12385
mxm merged 2 commits intoapache:masterfrom
ibzib:BEAM-10527

Conversation

@ibzib
Copy link
Copy Markdown

@ibzib ibzib commented Jul 28, 2020

Motivation

The main goals of migrating to pytest are:

  1. Get Junit structured test output (BEAM-10527).
  2. Replace PortableRunnerTest's bespoke timeout mechanism with pytest's (BEAM-9011). This also implicitly raises the timeout for all these tests from 60s to 600s, which should reduce the likelihood of timeout flakes (BEAM-8912).

Implementation

I originally wanted to do this in incremental changes, but I gradually realized a complete overhaul of these tests' configuration was needed. The main challenge was that flink_runner_test.py expected to be run as __main__, which is impossible with pytest. I basically reworked everything except the tests themselves; the tests themselves are unchanged.

Test parametrization

  • I left worker configuration in Gradle because it changes the test dependencies. I moved optimization and streaming into flink_runner_test.py because it removes the need to set up separate tox tasks, separate test result files, etc.
  • Since flink_job_server_driver, environment_type, and environment_config are all pipeline options, I decided to pass them to flink_runner_test.py by introducing a global pytest option, --test-pipeline-options. nose uses --test-pipeline-options for integration tests, so I figured this would be generally useful beyond just these tests in the future.

Bonus trivia

Prior to this change, we were running the exact same streaming test suite four times per Jenkins run.

Every flinkCompatibilityMatrix task ran the entirety of flink_runner_test.py which contained two classes: FlinkRunnerTest and FlinkRunnerTestOptimized. FlinkRunnerTestOptimized was basically the same thing as FlinkRunnerTest, but it added the pre_optimize=all experiment and skipped external transform tests, since the Python optimizer breaks external transforms (BEAM-7252). But we were also adding pre_optimize=all in Gradle, redundantly.

The old configuration looks like this:

dependsOn flinkCompatibilityMatrix(streaming: false, workerType: CompatibilityMatrixConfig.SDK_WORKER_TYPE.LOOPBACK)
dependsOn flinkCompatibilityMatrix(streaming: true, workerType: CompatibilityMatrixConfig.SDK_WORKER_TYPE.LOOPBACK)
dependsOn flinkCompatibilityMatrix(streaming: true, workerType: CompatibilityMatrixConfig.SDK_WORKER_TYPE.LOOPBACK, preOptimize: true)

Notice that pre-optimized batch is missing. This is because flinkCompatibilityMatrixBatchPreOptimize* would run FlinkRunnerTest with pre_optimize=all but without skipping the external transform tests, causing failure.

What about streaming, then? Well, the optimizer doesn't affect streaming pipelines at all:

if not options.view_as(StandardOptions).streaming:

So in one invocation of flinkValidatesRunner, flinkCompatibilityMatrixStreamingLoopback would run FlinkRunnerTest (without pre_optimize=all) and FlinkRunnerTestOptimized, then flinkCompatibilityMatrixStreamingPreOptimizeLoopback would run FlinkRunnerTest (with pre_optimize=all) and FlinkRunnerTestOptimized (with pre_optimize=all twice). Besides the skips in FlinkRunnerTestOptimized, all four tests would be doing the exact same thing.


Thank you for your contribution! Follow this checklist to help us incorporate your contribution quickly and easily:

  • Choose reviewer(s) and mention them in a comment (R: @username).
  • Format the pull request title like [BEAM-XXX] Fixes bug in ApproximateQuantiles, where you replace BEAM-XXX with the appropriate JIRA issue, if applicable. This will automatically link the pull request to the issue.
  • Update CHANGES.md with noteworthy changes.
  • If this contribution is large, please file an Apache Individual Contributor License Agreement.

See the Contributor Guide for more tips on how to make review process smoother.

Post-Commit Tests Status (on master branch)

Lang SDK Dataflow Flink Samza Spark Twister2
Go Build Status --- Build Status --- Build Status ---
Java Build Status Build Status
Build Status
Build Status
Build Status
Build Status
Build Status
Build Status Build Status
Build Status
Build Status
Build Status
Python Build Status
Build Status
Build Status
Build Status
Build Status
Build Status
Build Status
Build Status
Build Status
Build Status
--- Build Status ---
XLang Build Status --- Build Status --- Build Status ---

Pre-Commit Tests Status (on master branch)

--- Java Python Go Website
Non-portable Build Status Build Status
Build Status
Build Status
Build Status Build Status
Portable --- Build Status --- ---

See .test-infra/jenkins/README for trigger phrase, status and link of all Jenkins jobs.

@ibzib ibzib force-pushed the BEAM-10527 branch 2 times, most recently from 8ae28f6 to a51fed8 Compare July 28, 2020 02:00
@ibzib
Copy link
Copy Markdown
Author

ibzib commented Jul 28, 2020

Run Portable_Python PreCommit

@ibzib
Copy link
Copy Markdown
Author

ibzib commented Jul 28, 2020

R: @udim @mxm

Copy link
Copy Markdown
Contributor

@mxm mxm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR @ibzib! Great work on finding the test duplications. Having structured access to the test results via Jenkins will be very useful.

@mxm
Copy link
Copy Markdown
Contributor

mxm commented Jul 30, 2020

Run Java PreCommit

Copy link
Copy Markdown
Contributor

@mxm mxm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't find the published test results in Jenkins. Do we have to add this separately? https://ci-beam.apache.org/job/beam_PreCommit_Python2_PVR_Flink_Commit/6126/

@ibzib
Copy link
Copy Markdown
Author

ibzib commented Jul 31, 2020

I couldn't find the published test results in Jenkins. Do we have to add this separately? https://ci-beam.apache.org/job/beam_PreCommit_Python2_PVR_Flink_Commit/6126/

This is because publishing the test results relies on a change to the Jenkins job config, and I didn't want to run seed job because Flink PVR is a precommit and if I made a mistake, run seed job could break it for others. I tried testing locally on dockerized Jenkins, but I couldn't get it to work.

@ibzib
Copy link
Copy Markdown
Author

ibzib commented Jul 31, 2020

I got flinkCompatibilityMatrixPROCESS to pass on my machine by escaping the arguments via ${1@Q}. Apparently whatever shell Jenkins is using does not support this. I will have to find a better solution.

I have already spent a long time trying to fix quotes, so I can't help but wondering: why do we need flinkCompatibilityMatrixPROCESS in the first place, when it is not being run anywhere? If it's important, shouldn't we add it to some postcommit?

@ibzib
Copy link
Copy Markdown
Author

ibzib commented Jul 31, 2020

I have already spent a long time trying to fix quotes, so I can't help but wondering: why do we need flinkCompatibilityMatrixPROCESS in the first place, when it is not being run anywhere? If it's important, shouldn't we add it to some postcommit?

Another solution I had in mind was reworking the --environment_config option. JSON blobs are unwieldy, and overloading the --environment_config option is confusing to the user. We could make each field in the PROCESS --environment_config blob its own argument, and then reject these arguments when environment_type != PROCESS.

Copy link
Copy Markdown
Member

@udim udim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The approach to using pytest looks good. One comment.

@mxm
Copy link
Copy Markdown
Contributor

mxm commented Aug 3, 2020

Thanks for fixing the quoting issue!

I got flinkCompatibilityMatrixPROCESS to pass on my machine by escaping the arguments via ${1@Q}. Apparently whatever shell Jenkins is using does not support this. I will have to find a better solution.

I think that feature only works in newer versions of bash.

why do we need flinkCompatibilityMatrixPROCESS in the first place, when it is not being run anywhere? If it's important, shouldn't we add it to some postcommit?

flinkCompatibilityMatrixPROCESS was how we ran the PVR tests to avoid a dependency on the container build (for speed). I was under the assumption that we are still doing that. That probably changed when we added the external transform tests which require the Java container. I agree that we should at least have a post commit.

@ibzib
Copy link
Copy Markdown
Author

ibzib commented Aug 10, 2020

I have already spent a long time trying to fix quotes, so I can't help but wondering: why do we need flinkCompatibilityMatrixPROCESS in the first place, when it is not being run anywhere? If it's important, shouldn't we add it to some postcommit?

Another solution I had in mind was reworking the --environment_config option. JSON blobs are unwieldy, and overloading the --environment_config option is confusing to the user. We could make each field in the PROCESS --environment_config blob its own argument, and then reject these arguments when environment_type != PROCESS.

@mxm what do you think about https://issues.apache.org/jira/browse/BEAM-10671?

@mxm
Copy link
Copy Markdown
Contributor

mxm commented Aug 11, 2020

Another solution I had in mind was reworking the --environment_config option. JSON blobs are unwieldy, and overloading the --environment_config option is confusing to the user. We could make each field in the PROCESS --environment_config blob its own argument, and then reject these arguments when environment_type != PROCESS.

@mxm what do you think about https://issues.apache.org/jira/browse/BEAM-10671?

I think it makes sense. Especially for error reporting by having dedicated argument parsers for all environments parameters.

ibzib pushed a commit to ibzib/beam that referenced this pull request Aug 19, 2020
The default pytest timeout is 600s. Once all portable runner tests are migrated to pytest, we can use the pytest timeout instead of portable_runner_test's bespoke implementation. See apache#12385.
@ibzib ibzib force-pushed the BEAM-10527 branch 2 times, most recently from 6c233c2 to 2a0ad5d Compare October 1, 2020 01:46
@codecov
Copy link
Copy Markdown

codecov bot commented Oct 1, 2020

Codecov Report

Merging #12385 into master will increase coverage by 0.11%.
The diff coverage is 79.48%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master   #12385      +/-   ##
==========================================
+ Coverage   82.39%   82.50%   +0.11%     
==========================================
  Files         453      453              
  Lines       54623    54612      -11     
==========================================
+ Hits        45005    45059      +54     
+ Misses       9618     9553      -65     
Impacted Files Coverage Δ
sdks/python/apache_beam/io/fileio.py 95.80% <ø> (ø)
sdks/python/apache_beam/io/gcp/bigquery.py 80.23% <0.00%> (+0.14%) ⬆️
sdks/python/apache_beam/io/gcp/bigquery_tools.py 88.35% <0.00%> (ø)
...eam/testing/benchmarks/nexmark/nexmark_launcher.py 0.00% <0.00%> (ø)
...pache_beam/runners/interactive/interactive_beam.py 79.53% <66.66%> (ø)
...dks/python/apache_beam/options/pipeline_options.py 93.76% <70.58%> (ø)
sdks/python/apache_beam/transforms/environments.py 83.73% <83.33%> (ø)
.../apache_beam/options/pipeline_options_validator.py 98.69% <100.00%> (ø)
...ache_beam/runners/interactive/recording_manager.py 98.90% <100.00%> (ø)
... and 15 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 4161140...7219836. Read the comment docs.

@ibzib
Copy link
Copy Markdown
Author

ibzib commented Oct 1, 2020

Run Python Spark ValidatesRunner

@ibzib
Copy link
Copy Markdown
Author

ibzib commented Oct 1, 2020

@udim @mxm I rebased this to use environment_options instead of environment_config, bypassing previous issues with string parsing. PTAL

@mxm
Copy link
Copy Markdown
Contributor

mxm commented Oct 1, 2020

This looks good to me after rebasing. Thanks for porting this to pytest!

@mxm mxm merged commit bd56002 into apache:master Oct 1, 2020
# Run as
#
# pytest flink_runner_test.py \
# [--test_pipeline_options "--flink_job_server_jar=/path/to/job_server.jar \
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--test-pipeline-options

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah, --test_pipeline_options is now required (even though it should be possible to leave it empty). Boyuan, would you mind filing a PR to fix this?

# pytest flink_runner_test.py \
# [--test_pipeline_options "--flink_job_server_jar=/path/to/job_server.jar \
# --environment_type=DOCKER"] \
# [FlinkRunnerTest.test_method, ...]
Copy link
Copy Markdown
Contributor

@boyuanzz boyuanzz Oct 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And the test filter here doesn't work for me properly. The working version for me is

pytest flink_runner_test.py::TestClass:test_case --test-pipeline-options "--flink_job_server_jar=XXX --environment_type=XXX "

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants