-
Notifications
You must be signed in to change notification settings - Fork 641
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 Random Seed Functionality in TestFramework #288
Comments
Closed
I'd like to tackle this one. Should be a good learning exercise. |
Great. I have assigned it to you. |
This was referenced Nov 18, 2021
NightOwl888
added a commit
that referenced
this issue
Nov 22, 2021
…peatable (Fixes #288) (#547) * Lucene.Net.TestFramework.Util.LuceneTestCase: Added message to the test result on how to set a fixed random seed to reproduce the test result (pass or fail). * Lucene.Net.TestFramework.Util: Added customized TestFixtureAttribute, and NUnitTestFixtureBuilder along with RandomSeedAttribute and LuceneRandomSeedInitializer to fix the broken randomized seed functionality so we can repeat test runs reliably. * BREAKING: Lucene.Net.Util.StringHelper.GOOD_FAST_HASH_SEED: converted from a static field to a property and marked obsolete. Added a new property GoodFastHashSeed. Removed SystemProperties call to populate the value of the field, since NUnit only allows us to generate a seed per test, and we need a way to inject the seed value for repeatability. * Lucene.Net.TestFramework.Support.Util.LuceneRandomSeedInitializer: Added line to set StringHelper.goodFastHashSeed when the test framework is attached. * Lucene.Net.TestFramework.Util.LuceneTestCase: Stow Random instance in test properties if we are in a suite context * Lucene.Net.TestFramework: Reworked LuceneRandomSeedIntiailizer and changed RandomSeedAttribute to be an assembly-level attribute * Lucene.Net.TestFramework: Removed support for Randomizer.InitialSeed and store the seed in a property of the test fixture (instance-based rather than static) * Lucene.Net.Tests.TestFramework.Support.TestApiConsistency: Added exclusion for RandomSeed constant * Lucene.Net.TestFramework.Util.TestRuleSetupAndRestoreClassEnv: Changed system property to prefer "tests:culture" instead of "tests:locale" to set the culture, but left "tests:locale" in for backward/java compatibility. * Lucene.Net.TestFramework: Created RandomizedContext class to store as an NUnit test property for each test. This allows us to add additional strongly-typed properties to the test without wrapping the class. Changed to use J2N.Randomizer and changed all seeds to long rather than int. Converted the number for setting the random seed to hexadecimal and updated the message to add the setting for the current culture to the attributes/.runsettings file. * BREAKING: Added LuceneSetUpFixtureBuilder class to load either a subclass or our default instance of LuceneTestFrameworkInitializer. Also added LuceneTestCase.SetUpFixture to control initialization of LuceneTestFrameworkInitializer so it is only called on setup and teardown for the assembly. Added Initialize() method to LuceneTestFrameworkInitializer that must be used to set the factories. * Lucene.Net.TestFramework.Util.LuceneTestCase: Only print out the detailed random repeat message on failure or error * BREAKING: Lucene.Net.TestFramework.Util.LuceneTestCase: Deprecated GetClassType() method and added TestType property * BREAKING: Lucene.Net.TestFramework.Util.AbstractBeforeAfterRule: Removed LuceneTestCase parameter from Before() and After() methods. * Lucene.Net.Util.LuceneRandomSeedInitializer: Added overload of InitializeTestFixture that accepts RandomizedContext so NUnitTestFixtureBuilder doesn't have to deal with setting NUnit properties. Also added RandomizedContext.CurrentTestAssembly property. * Lucene.Net.TestFramework.Util: Added UseTempLineDocsFileAttribute and a UseTempLineDocFileRule to scan for it and execute the file decompression and cleanup. Removed the unnecessary Startup.cs files that only served the purpose of getting NUnit to recognize LuceneTestFrameworkInitializer in the assembly scan. * Lucene.Net.TestFramework.Util.TestRuleSetupAndRestoreClassEnv: Allow NUnit's [SetCulture] attribute to be used to set the culture * Lucene.Net.TestFramework.Util.LuceneTestCase: Updated repeat instructions to use NUnit's SetCulture attribute, since NUnit property attributes are not currently read by the test framework * Lucene.Net.TestFramework.Analysis.BaseTokenStreamTestCase: Switched from using System.Random to J2N.Randomizer * Lucene.Net.Tests.Analysis.Common.Analysis.Core.TestRandomChains: Switched from using System.Random to J2N.Randomizer. Also added feature to export a random SynonymMap as source code. * azure-pipelines.yml: set maximumAllowedFailures to 0 * SWEEP: Marked all of the latest test failures with [AwaitsFix] attribute and an issue URL. * Lucene.Net.Classification.KNearestNeighborClassifierTest::TestPerformance(): Ignore in net461, since it runs a bit slow in that environment. * Lucene.Net.Index.TestIndexWriter::TestThreadInterruptDeadlock(): Added [AwaitsFix] attribute, as this is sometimes failing (see #544) * Lucene.Net.Tests.Join.TestJoinUtil::TestMultiValueRandomJoin(): Added [AwaitsFix] attribute, since this test is failing on .NET Framework x86 in Release mode. * SWEEP: Changed all test instances of System.Random to J2N.Randomizer. APIs remain as System.Random, since J2N.Randomizer is a subclass. * Lucene.Net.TestFramework.Util.MethodInfoComparer: Made into singleton * Lucene.Net.Classification.KNearestNeighborClassifierTest::TestPerformance(): Adjusted limit from 2 min to 2.5 min for .NET Framework, since it runs a bit slow in CI.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The random seed that is set to
StringHelper.GOOD_FAST_HASH_SEED
through thetests.seed
system property in Java currently is the same as the seed that NUnit uses inNUnit.Framework.TestContext.CurrentContext.Random
. If we continue using NUnit'sRandom
property, more research is needed to figure out how to set that seed the way the NUnit designers intended so it can be documented for end users.During testing, I noticed that NUnit does set the seed to a consistent pseudo-random value, so the same test can be run over and over with exactly the same random setup. However, the seed is re-generated when the code in the project under test is changed. I noted that NUnit writes the seed to a file named
nunit_random_seed.tmp
in thebin
folder of the test project when run in Visual Studio.A Typical Testing Scenario in Lucene
tests.seed
system property to the same hexadecimal string that caused the test to failTesting in .NET
All we have been able to do is get the same test to fail multiple times, but that breaks as soon as any code is changed. We could probably revert back if we save a copy of the
nunit_random_seed.tmp
, but this is very complicated to do in addition to debugging, and not very intuitive.We are missing:
I suspect that although setting the seed cannot be done publicly, we can hack it by using .NET Reflection to set an internal field. There was some discussion about setting it through an attribute, but it doesn't sound like that has been implemented.
I haven't looked into what it will take to extend NUnit to attach the random seed to the test message that is reported. One option (but not a very good one) would be to change the
Lucene.Net.TestFramework.Assert
class to add the random seed to all of test messages. The main thing we need is to read the seed value. The only place it seems to be exposed is in thebin/nunit_random_seed.tmp
file, but it would be preferable to read it through a property within the test session.Testing Lucene.NET Itself
For end users, the above would solve all of the issues. However, for Lucene.NET we often need to generate the same conditions as Java to determine where the execution paths diverge. This is a problem because the NUnit Random class (probably) isn't the same implementation as the Java Random class. Also, in Java the random seed is a
long
, but in .NET, it is anint
.We have ported the Java Random class in
J2N
, named Randomizer. Ideally, we would use this implementation during testing. However, NUnit doesn't seem to have a way to inject a custom implementation ofRandom
nor does it have a way to read the seed it uses to seed a new instance ofRandomizer
for the test framework or a way to override that setting manually during debugging.Ideal Solution
System.DateTime.UtcNow.Ticks
.long
.J2N.Randomizer
class, which the getter of theLuceneTestFramework.Random
property would provide and cache.tests:seed
to be set to a hexadecimal string, which if set would override the auto-generated random seed used in step 3.Note that the ideal solution doesn't necessarily involve NUnit in the equation. With Java's Random class ported and "System Properties" solved in a way that doesn't involve hacking the system's environment variables when debugging, we are much closer to fixing this to make it compatible with Java Lucene so we can test apples to apples.
The main thing we are missing is writing the random seed out into the test message with hexadecimal formatting (the same string that is used in Lucene). Other than that, setting up the system property to override the automatically generated seed should be fairly straightforward.
The text was updated successfully, but these errors were encountered: