Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KAFKA-12459; Use property testing library for raft event simulation tests #10323

Merged
merged 4 commits into from
Mar 18, 2021

Conversation

hachikuji
Copy link
Contributor

This patch changes the raft simulation tests to use jqwik, which is a property testing library. This provides two main benefits:

  • It simplifies the randomization of test parameters. Currently the tests use a fixed set of Random seeds, which means that most builds are doing redundant work. We get a bigger benefit from allowing each build to test different parameterizations.
  • It makes it easier to reproduce failures. Whenever a test fails, jqwik will report the random seed that failed. A developer can then modify the @Property annotation to use that specific seed in order to reproduce the failure.

Note that I have resisted making logical changes to the tests themselves. The only difference is the way the parameters are specified.

Committer Checklist (excluded from commit message)

  • Verify design and implementation
  • Verify test coverage and CI build status
  • Verify documentation (including upgrade notes)

@hachikuji hachikuji force-pushed the KAFKA-12459-improve-raft-sim-tests branch from 96cb294 to 35ab2c9 Compare March 15, 2021 23:11
@hachikuji hachikuji force-pushed the KAFKA-12459-improve-raft-sim-tests branch from 35ab2c9 to ec936bb Compare March 15, 2021 23:21
Copy link
Member

@dajac dajac left a comment

Choose a reason for hiding this comment

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

This is pretty cool framework! The PR LGTM. I just left a minor suggestion.

Copy link
Member

@chia7712 chia7712 left a comment

Choose a reason for hiding this comment

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

Run this patch with junit 5.8.0-M1. works well so +1

@@ -525,33 +430,27 @@ void schedule(Runnable action, int delayMs, int periodMs, int jitterMs) {
}

void runUntil(Supplier<Boolean> exitCondition) {
while (!exitCondition.get()) {
if (queue.isEmpty())
for (int iteration = 0; iteration < MAX_ITERATIONS; iteration++) {
Copy link
Member

Choose a reason for hiding this comment

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

How about setting @Timeout instead of MAX_ITERATIONS?

@ijuma
Copy link
Member

ijuma commented Mar 16, 2021

Nice! How did we pick jqwik?

@hachikuji
Copy link
Contributor Author

I can't claim to have searched all the library options extensively. I found out about jqwik from @stanislavkozlovski. The documentation seemed clear and it took almost no time to get something working. I do like how extensible the framework seems. I thought I might need some of that here, but it turned out to be a pretty simple usage within the standard API.

@ijuma
Copy link
Member

ijuma commented Mar 16, 2021

@hachikuji Sounds good. Can we take a quick look at the two alternatives mentioned in the following blog post?
https://blog.johanneslink.net/2020/01/28/why-is-pbt-not-popular-in-java/

I think you choose the right one, but good to do a bit of due diligence as future Java-based property based tests will rely on whatever we pick here.

@stanislavkozlovski
Copy link
Contributor

For what it's worth I evaluated jqwik vs Quickcheck and had the following bullet-point summaries:

Quickcheck

  • 819 stars
  • 10-year old library
  • v1.0 released Nov 22, 2020
  • 25 open issues
  • 55 commits in the last year
  • MIT License
  • light documentation
  • supports shrinking

Jqwik

  • 260 stars
  • 5-year old library
  • v1.5 release Feb 2021
  • 16 open issues
  • 1039 commits in the last year
  • EPL-2.0 License
  • extensive documentation
  • very configurable
  • supports shrinking

My reasoning to prefer Jqwik was that it seemed more actively maintained, had good interfaces, had very extensive documentation (I value this heavily) and most importantly supports programmatic parameter generation, meaning it allows you to easily express the dependencies of randomized input. I got the notion that this random input dependency generation is one of the trickier things when writing more complex test cases from this blog post.

Jqwik has some other interesting features like collecting and reporting statstics on the data it generates, allowing you to inspect what the generated data is and whether it's useful or can be tweaked.

@ijuma
Copy link
Member

ijuma commented Mar 16, 2021

Thanks, this is very helpful. Since this is EPL 2, we need to check https://apache.org/legal/resolved.html#weak-copyleft-licenses

@hachikuji
Copy link
Contributor Author

@ijuma Thanks for the link. EPL 2.0 is listed as a "weak copyleft" license, similar to Jersey under CDDL. The document says that we can include a binary dependence as long as it is appropriately labeled. I've updated the NOTICE file with language similar to the note about Jersey.

@hachikuji hachikuji force-pushed the KAFKA-12459-improve-raft-sim-tests branch from 0501c45 to 43035c7 Compare March 17, 2021 16:31
@chia7712
Copy link
Member

unrelated to this PR. forRandomRunning is not used. Maybe we can remove it in this PR? Also, random of RaftNode is not used also.

@hachikuji
Copy link
Contributor Author

@chia7712 I removed forRandomRunning here: #10309.

Copy link
Member

@jsancio jsancio left a comment

Choose a reason for hiding this comment

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

Very cool. Excited to use this in other tests.


scheduler.runUntil(() -> cluster.allReachedHighWatermark(20, nonPartitionedNodes));
}
@Property(tries = 100)
Copy link
Member

Choose a reason for hiding this comment

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

Hmm. These simulation tests are already the slowest suite in raft:test. I git fetch the PR and it looks like they still run when calling ./gradlew raft:test. Is there away to set this to a smaller number (2) as the default and override it if the user wants to run them with 100 tries?

Btw, 5 (number of possible voters) * 6 (number of possible observers) is 30 which is much smaller than 100. I assume that the library will run the same configuration with multiple seeds.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The PR is reducing the number of runs by quite a lot. I justified this on account of the randomized seed which allow more of the builds to be doing useful (i.e. non-redundant) work. I think there are a bunch of improvements we can make to improve execution time overall. Also I suspect there was a regression since these used to execute much faster. Really I'd like to get to the point where we can run thousands of simulations on each build without significantly adding build time.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was inspired to take a look and found the big regression. The way we catch NoSuchElementException in MockLog was killing the performance of these tests because of need to fill in the stack trace. I tested locally with a fix and it brought the local time for this test from over 4 minutes to 48 seconds. On trunk, this test is taking more than 16 minutes for me, so overall this patch will be a major improvement.

Copy link
Member

Choose a reason for hiding this comment

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

Very cool. I made the same change to KafkaMetadataLog: #10344

}
@Property(tries = 100)
void canElectInitialLeader(
@ForAll Random random,
Copy link
Member

Choose a reason for hiding this comment

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

I assume that @ForAll will cause the library to run this test multiple times with different random seeds. If so is there a way to tell the library to only run it once for some random seed?

Copy link
Contributor Author

@hachikuji hachikuji Mar 17, 2021

Choose a reason for hiding this comment

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

Probably, but here I want it to run with multiple random seeds.

Copy link
Member

@jsancio jsancio left a comment

Choose a reason for hiding this comment

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

LGTM.

@hachikuji
Copy link
Contributor Author

hachikuji commented Mar 18, 2021

I am planning to merge this shortly if there are no objections. I double-checked with @junrao about the note added to NOTICE in regard to the jqwik license.

@hachikuji hachikuji merged commit 8ef1619 into apache:trunk Mar 18, 2021
ijuma added a commit to confluentinc/kafka that referenced this pull request Mar 19, 2021
Conflicts:
* build.gradle: keep `dependencySubstitution` Confluent addition in
`resolutionStrategy` and take upstream changes.

Commits:
* apache-github/trunk:
  KAFKA-12503: inform threads to resize their cache instead of doing so for them (apache#10356)
  KAFKA-10697: Remove ProduceResponse.responses (apache#10332)
  MINOR: Exclude KIP-500.md from rat check (apache#10354)
  MINOR: Move `configurations.all` to be a child of `allprojects` (apache#10349)
  MINOR: Remove use of `NoSuchElementException` in `KafkaMetadataLog` (apache#10344)
  MINOR: Start the broker-to-controller channel for request forwarding (apache#10340)
  KAFKA-12382: add a README for KIP-500 (apache#10227)
  MINOR: Fix BaseHashTable sizing (apache#10334)
  KAFKA-10357: Add setup method to internal topics (apache#10317)
  MINOR: remove redundant null check when testing specified type (apache#10314)
  KAFKA-12293: Remove JCenter from buildscript and delete buildscript.gradle
  KAFKA-12491: Make rocksdb an `api` dependency for `streams` (apache#10341)
  KAFKA-12454: Add ERROR logging on kafka-log-dirs when given brokerIds do not  exist in current kafka cluster (apache#10304)
  KAFKA-12459; Use property testing library for raft event simulation tests (apache#10323)
  MINOR: fix failing ZooKeeper system tests (apache#10297)
  MINOR: fix client_compatibility_features_test.py (apache#10292)
@ijuma ijuma added the kraft label Aug 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants