Home | About | Sematext search-lucene.com search-hadoop.com
 Search Lucene and all its subprojects:

Switch to Plain View
Lucene, mail # dev - [Important] New test framework, differences, features, etc.


Copy link to this message
-
[Important] New test framework, differences, features, etc.
Dawid Weiss 2012-04-15, 14:45
Ah... such a relief to finally have it committed even if this means
the work has just begun on straightening it all out. So.

1) WHAT'S BEEN DONE?

The primary objective was to pull out "randomized" runner from Lucene
and make it available as a separate project for reuse in other
projects. This kind of grew into two things:

a) RandomizedRunner - a runner that has built-in support for
randomization and other interesting features,
b) junit4-ant - an ANT task for running JUnit4 tests in parallel JVMs,
with an aggregation of events, balancing, logs, different (from
standard ANT) reporting and forked JVM crash resilience.

Everything above is heavily covered with unit tests (the code is on
github here: https://github.com/carrotsearch/randomizedtesting).

LUCENE-3808 removes LuceneTestCaseRunner, replacing it with
RandomizedRunner. It also modifies build scripts to run junit4-ant
instead of ANT's default <junit>.

2) HOW DOES IT AFFECT ME AS A LUCENE/ SOLR DEVELOPER?

- The most visible change is that 'random' field in LuceneTestCase is
gone. This change was motivated by the fact that the field's value was
read from places where it shouldn't be read, passed to places where it
shouldn't be passed, etc. Instead, the Random instance for a given
scope (see below) can be acquired from a static method in
LuceneTestCase called random(). In the essence, you can just add
brackets around your previous random field references and it _should_
work out of the box. There are differences though: Random object
returned by random() is valid only for the scope it was created for.
So any of the following will end up in an exception: saving a Random
instance in a static scope (@BeforeClass) to a field and reusing it in
a test, passing a Random instance from one thread to another, saving a
Random instance to a field in one test, using it in another, etc. In
short: the result of random() is per-thread and only valid for the
scope (test method, hook) it was acquired for. You _can_ call random()
from non-test threads -- they will be given their own thread-local
Random instances.

- The 'random seed' is a single HEX-encoded long. The "three seeds"
from before are gone. Everything is a derivative of the initial master
seed.

- I provided a 'help on syntax' for test properties. Type:

ant test-help

and the most common use case scenarios will be dumped to your console.

- A notable difference is that 'tests.iter' property has been renamed
to 'tests.iters' (you'll get a build failure and a message if you try
to use the former one). I could add a fallback but I'd rather not
introduce any more aliases.

- "tests.iters" is no longer a poor-man's loop. It really re-runs a
duplicate of a given test (or tests), including any @Before/@After
hooks and setups. In theory, this means it is now possible to
reiterate ANY test, no matter how complex. If it doesn't depend on
static state, it can be repeated. This also links to how seed is used.
It's probably best explained on an example:

ant -Dtests.seed=deadbeef -Dtests.iters=3
-Dtestcase=TestSubScorerFreqs test-core

the above will result in 3 executions of every test in
TestSubScorerFreqs. What you'll get on the console is:

   [junit4] <JUnit4> says hello. Random seed: deadbeef
   [junit4] Expected execution time on JVM J0:     0.02s
   [junit4] Executing 1 suite with 1 JVM.
   [junit4] Running org.apache.lucene.search.TestSubScorerFreqs
   [junit4] Tests run:   9, Failures:   0, Errors:   0, Skipped:   0,
Time:  0.45s
   [junit4]
   [junit4] JVM J0:     0.36 ..     0.96 =     0.60s
   [junit4] Execution time total: 0.98 sec.
   [junit4] Tests summary: 1 suite, 9 tests

and if you peek at the log file with test results
(build/core/test/tests-report.txt) you'll see the details of each
executed test:

Executing 1 suite with 1 JVM.
Running org.apache.lucene.search.TestSubScorerFreqs
OK      0.04s | TestSubScorerFreqs.testTermQuery {#0
seed=[DEADBEEF:BAE943E3CC27A0F]}
OK      0.01s | TestSubScorerFreqs.testTermQuery {#1
seed=[DEADBEEF:BFF828C20800B123]}
OK      0.01s | TestSubScorerFreqs.testTermQuery {#2
seed=[DEADBEEF:3111BE1E59C4F9E8]}
OK      0.02s | TestSubScorerFreqs.testBooleanQuery {#0
seed=[DEADBEEF:3DDFB93BCC712A41]}
OK      0.01s | TestSubScorerFreqs.testBooleanQuery {#1
seed=[DEADBEEF:898905C7F8B3E16D]}
OK      0.01s | TestSubScorerFreqs.testBooleanQuery {#2
seed=[DEADBEEF:760931BA977A9A6]}
OK      0.01s | TestSubScorerFreqs.testPhraseQuery {#0
seed=[DEADBEEF:A7ADE8DE1DB7CA0B]}
OK      0.01s | TestSubScorerFreqs.testPhraseQuery {#1
seed=[DEADBEEF:13FB542229750127]}
OK      0.01s | TestSubScorerFreqs.testPhraseQuery {#2
seed=[DEADBEEF:9D12C2FE78B149EC]}
Tests run:   9, Failures:   0, Errors:   0, Skipped:   0, Time:  0.45s

Note that tests.iters=3 resulted in every test case executed three
times, but they all count individually (so the reported total is 9
tests). What's also clearly seen is that the master seed is constant
for all tests but each repetition gets a (predictable) derivative of
the random seed. This way you can reiterate N times over a test, each
time with a different seed. Now, compare this to:

ant -Dtests.seed=deadbeef:cafebabe -Dtests.iters=3
-Dtestcase=TestSubScorerFreqs test-core

The log file now will be:

Executing 1 suite with 1 JVM.
Running org.apache.lucene.search.TestSubScorerFreqs
OK      0.04s | TestSubScorerFreqs.testTermQuery {#0 seed=[DEADBEEF:CAFEBABE]}
OK      0.01s | TestSubScorerFreqs.testTermQuery {#1 seed=[DEADBEEF:CAFEBABE]}
OK      0.01s | TestSubScorerFreqs.testTermQuery {#2 seed=[DEADBEEF:CAFEBABE]}
OK      0.02s | TestSubScorerFreqs.testBooleanQuery {#0
seed=[DEADBEEF:CAFEBABE]}
OK      0.01s | TestSubScorerFreqs.testBooleanQuery {#1
seed=[DEADBEEF:CAFEBABE]}
OK      0.01s | TestSubScorerFreqs.testBooleanQuery {#2
seed=[DEADBEEF:CAFEBABE]}
OK      0.01s | TestSubScorerFreqs.testPhraseQuery {#0 seed=[DEADBEEF:CAFEBABE]}
OK      0.01s | TestSubScorerFreqs.testPhraseQuery {#1 seed=[DEADBEEF:CAFEBABE]}
OK      0.01s | TestSubScorerFreqs
+
Steven A Rowe 2012-04-15, 16:21
+
Dawid Weiss 2012-04-15, 17:35
+
Steven A Rowe 2012-04-15, 17:49
+
Dawid Weiss 2012-04-15, 19:04
+
Mark Miller 2012-04-16, 02:42
+
Dawid Weiss 2012-04-16, 06:56
+
Steven A Rowe 2012-04-16, 12:53
+
Dawid Weiss 2012-04-16, 13:06
+
Yonik Seeley 2012-04-15, 14:58
+
Dawid Weiss 2012-04-15, 15:21
+
Uwe Schindler 2012-04-16, 13:09
+
Steven A Rowe 2012-04-16, 13:13
+
Dawid Weiss 2012-04-16, 13:15
+
Uwe Schindler 2012-04-16, 13:51
+
Robert Muir 2012-04-16, 14:00
+
Dawid Weiss 2012-04-16, 13:13
+
Steven A Rowe 2012-04-16, 13:34
+
Steven A Rowe 2012-04-16, 12:57
+
Dawid Weiss 2012-04-16, 13:03
+
Steven A Rowe 2012-04-16, 13:05
+
Dawid Weiss 2012-04-16, 13:08
+
Andrzej Bialecki 2012-04-16, 14:01
+
Dawid Weiss 2012-04-16, 17:14
+
Steven A Rowe 2012-04-16, 13:28
+
Mark Miller 2012-04-16, 17:21
+
Dawid Weiss 2012-04-16, 17:29