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

Fix test reproducability in AbstractBuilderTestCase setup #32403

Merged
merged 7 commits into from
Aug 10, 2018

Conversation

cbuescher
Copy link
Member

Currently AbstractBuilderTestCase generates certain random values in its
beforeTest() method annotated with @before only the first time that a test
method in the suite is run. This changes the values of subsequent random values
and has the effect that when running single methods from a test suite with
"-Dtests.method=*", the random values it sees are different from when the same
test method is run as part of the whole test suite. This makes it harder to use
the reproduction lines logged on failure.

This changes the above method so that beforeTest will do the same call to the
random value source each time a test method is run, so reproduction by running
just one method is possible again.

Closes #32400

Currently AbstractBuilderTestCase generates certain random values in its
`beforeTest()` method annotated with @before only the first time that a test
method in the suite is run. This changes the values of subsequent random values
and has the effect that when running single methods from a test suite with
"-Dtests.method=*", the random values it sees are different from when the same
test method is run as part of the whole test suite. This makes it harder to use
the reproduction lines logged on failure.

This changes the above method so that `beforeTest` will do the same call to the
random value source each time a test method is run, so reproduction by running
just one method is possible again.

Closes elastic#32400
@cbuescher cbuescher added >enhancement >test Issues or PRs that are addressing/adding tests v7.0.0 v6.4.0 :Search/Search Search-related issues that do not fall into other categories labels Jul 26, 2018
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-search-aggs

Copy link
Contributor

@jimczi jimczi left a comment

Choose a reason for hiding this comment

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

Good catch @cbuescher , I left a comment

// creating ServiceHolder just once. The other times are necessary so that further random
// generation stays the same for all test that is run, otherwise reproducability breaks
Settings indexSettings = createTestIndexSettings();
long now = randomNonNegativeLong();
Copy link
Contributor

Choose a reason for hiding this comment

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

can we initialize indexVersionCreated and now in the BeforeClass as static members like we do for nodeSetttings and index ?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good point, I will change this for now, I don't think we need different values for now for different test cases. For indexVersionCreated I find this to be more difficult. We have at least three tests (ParentIdQueryBuilderTests, HasChildQueryBuilderTests, HasParentQueryBuilderTests) overwriting createTestIndexSettings to create a specialized version setting (it seems to be restricted to CURRENT). I'm not sure we can use this mechanism of overwriting default versions in specific tests if the call this in a static context in BeforeClass. I might have missed something though, let me know what you think.

Christoph Büscher added 2 commits August 6, 2018 15:15
 Conflicts:
	test/framework/src/main/java/org/elasticsearch/test/AbstractBuilderTestCase.java
@cbuescher
Copy link
Member Author

@jimczi thanks for the review, I updated the PR by adressing one of your suggestions, left a question for the other. Let me know what you think about it.

// the two following ranomized parameters are drawn every run, even though we use them in
// creating ServiceHolder just once. The other times are necessary so that further random
// generation stays the same for all test that is run, otherwise reproducability breaks
Settings indexSettings = createTestIndexSettings();
Copy link
Member

Choose a reason for hiding this comment

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

The proposed fix is ok, but I wonder if the following wouldn't be better:

    @Before
    public void beforeTest() throws Exception {
        if (serviceHolder == null) {
            assert serviceHolderWithNoType == null;
            long masterSeed = SeedUtils.parseSeed(RandomizedTest.getContext().getRunnerSeedAsString());
            RandomizedTest.getContext().runWithPrivateRandomness(masterSeed, (Callable<Void>) () -> {
                serviceHolder = new ServiceHolder(nodeSettings, indexSettings(), getPlugins(), AbstractBuilderTestCase.this, true);
                serviceHolderWithNoType = new ServiceHolder(nodeSettings, indexSettings(), getPlugins(), AbstractBuilderTestCase.this, false);
                return null;
            });
        }
        serviceHolder.clientInvocationHandler.delegate = this;
        serviceHolderWithNoType.clientInvocationHandler.delegate = this;
    }

The idea is to execute this conditional initialization step under the suite randomness rather than the method randomness. If we don't want to parse the suite seed back from a string we could also generate our own suite seed, the important bit is that we generate it in the beforeClass which is executed under the suite randomness (master seed). I find that this way what we are doing is clearer. The proposed fix is good but can easily be reverted by mistake by just moving lines around.

Copy link
Member Author

Choose a reason for hiding this comment

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

Great suggestion, I added this.

@javanna
Copy link
Member

javanna commented Aug 8, 2018

I left one comment, I think it would also be good to add a test for this but it's quite tricky to do and I don't have a good idea around that. I had a quick look at some of our base test classes to see where we do similar things (conditionally initialize static variables in before methods, and generate random values as part of such init methods) and I think that ESClientYamlSuiteTestCase and ESRestTestCase have the same issue.

@cbuescher
Copy link
Member Author

@javanna thanks for the suggestion, I added it in another commit, together with some comment summing up the resoning for it so we don't forget why we are doing this here. Can you take another look?

: VersionUtils.randomVersionBetween(random(), Version.V_6_0_0, Version.CURRENT);
return Settings.builder()
.put(IndexMetaData.SETTING_VERSION_CREATED, indexVersionCreated)
.build();
}

protected IndexSettings indexSettings() {
Copy link
Member

Choose a reason for hiding this comment

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

could this be static?

Copy link
Member

@javanna javanna left a comment

Choose a reason for hiding this comment

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

LGTM thanks @cbuescher !

@cbuescher cbuescher merged commit 22f7b03 into elastic:master Aug 10, 2018
cbuescher pushed a commit that referenced this pull request Aug 10, 2018
Currently AbstractBuilderTestCase generates certain random values in its
`beforeTest()` method annotated with @before only the first time that a test
method in the suite is run while initializing the serviceHolder that we use for
the rest of the test. This changes the values of subsequent random values
and has the effect that when running single methods from a test suite with
"-Dtests.method=*", the random values it sees are different from when the same
test method is run as part of the whole test suite. This makes it hard to use
the reproduction lines logged on failure.

This change runs the inialization of the serviceHolder and the randomization
connected to it using the test runners master seed, so reproduction by running
just one method is possible again.

Closes #32400
cbuescher pushed a commit that referenced this pull request Aug 10, 2018
Currently AbstractBuilderTestCase generates certain random values in its
`beforeTest()` method annotated with @before only the first time that a test
method in the suite is run while initializing the serviceHolder that we use for
the rest of the test. This changes the values of subsequent random values
and has the effect that when running single methods from a test suite with
"-Dtests.method=*", the random values it sees are different from when the same
test method is run as part of the whole test suite. This makes it hard to use
the reproduction lines logged on failure.

This change runs the inialization of the serviceHolder and the randomization
connected to it using the test runners master seed, so reproduction by running
just one method is possible again.

Closes #32400
cbuescher pushed a commit that referenced this pull request Aug 10, 2018
cbuescher pushed a commit that referenced this pull request Aug 10, 2018
jasontedor added a commit to jasontedor/elasticsearch that referenced this pull request Aug 13, 2018
…listeners

* elastic/master: (58 commits)
  [ML] Partition-wise maximum scores (elastic#32748)
  [DOCS] XContentBuilder#bytes method removed, using BytesReference.bytes(docBuilder) (elastic#32771)
  HLRC: migration get assistance API (elastic#32744)
  Add a task to run forbiddenapis using cli (elastic#32076)
  [Kerberos] Add debug log statement for exceptions (elastic#32663)
  Make x-pack core pull transport-nio (elastic#32757)
  Painless: Clean Up Whitelist Names (elastic#32791)
  Cat apis: Fix index creation time to use strict date format (elastic#32510)
  Clear Job#finished_time when it is opened (elastic#32605) (elastic#32755)
  Test: Only sniff host metadata for node_selectors (elastic#32750)
  Update scripted metric docs to use `state` variable (elastic#32695)
  Painless: Clean up PainlessCast (elastic#32754)
  [TEST] Certificate NONE not allowed in FIPS JVM (elastic#32753)
  [ML] Refactor ProcessCtrl into Autodetect and Normalizer builders (elastic#32720)
  Access build tools resources (elastic#32201)
  Tests: Disable rolling upgrade tests with system key on fips JVM (elastic#32775)
  HLRC: Ban LoggingDeprecationHandler (elastic#32756)
  Fix test reproducability in AbstractBuilderTestCase setup (elastic#32403)
  Only require java<version>_home env var if needed
  Tests: Muted ScriptDocValuesDatesTests.testJodaTimeBwc
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
>enhancement :Search/Search Search-related issues that do not fall into other categories >test Issues or PRs that are addressing/adding tests v6.4.0 v6.5.0 v7.0.0-beta1
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants