Bug 1192

Summary: Some test cases fail to clean up properly (missing DoTeardown)
Product: ns-3 Reporter: Claudio <claudio-daniel.freire>
Component: test frameworkAssignee: Mathieu Lacage <mathieu.lacage>
Status: REOPENED ---    
Severity: minor CC: mathieu.lacage, ns-bugs, tomh
Priority: P5    
Version: ns-3-dev   
Hardware: All   
OS: All   
Bug Depends on:    
Bug Blocks: 1096    
Attachments: Teardown patch
Another set of teardown changes
Patchset with SeedManager::SetSeed/Run fixes
Patchset with Config::Reset implementation
Patchset with complete set of test repeatability fixes
Updated reference PCAP traces for tests
Monolithic patch

Description Claudio 2011-06-17 09:11:20 EDT
Created attachment 1167 [details]
Teardown patch

The attached patch fixes a few test cases that did not do proper teardown.

This issue surfaced while trying to code some benchmarking framework by repeated execution of tests and examples (to assess a future patch's impact on performance).
Comment 1 Mitch Watrous 2011-06-17 18:07:51 EDT
Bug closed.

ns-3-dev changeset: 55f494c59bf2
Comment 2 Claudio 2011-06-27 08:57:57 EDT
Created attachment 1176 [details]
Another set of teardown changes

Hi there again.

I'm reopening it since, while working with this bencharking stuff, I noticed some more cases (though subtle) of improper teardown.

Especially in the case of failed tests, the simulator keeps alive (it's not destroyed), and this brought some trouble (of the segmentation fault at times) later on.

Also, many tests change NS3 configuration values, and they don't restore them to the usual defaults. Because of a lack of configuration getters, the patch attached only sets them back to the defaults documented in NS3's doxy, but the best thing would be to make backups of them and restore to their previous values.

In any case, this patch is a lot bigger, and it only fixes the tests for the case where you want to run several tests in succession, in the same process. ./waf check doesn't run tests this way, so there should be no difference there.

IF this patch is accepted, I can post the benchmarking stuff (without this patch, benchmark results aren't significant because of failed test runs).
Comment 3 Mathieu Lacage 2011-07-06 16:50:43 EDT
In the past, I was as frustrated as you by this and put together similar patches but I eventually gave up because I could not see how we could make sure that all our global variables are reset to the right state after a test runs. So, I thought: if I cannot get this right 100%, what is the point of making people believe it might work and suffer when it does not ? i.e., I chose to live with test.py (even though I hate this).

I would tend to feel like making this bug as WONTFIX based on the above unless you feel that you can really make the whole attribute system be nicely reset upon test completion to make sure different tests do not interfere on each other.

(In reply to comment #2)
> Created attachment 1176 [details]
> Another set of teardown changes
> 
> Hi there again.
> 
> I'm reopening it since, while working with this bencharking stuff, I noticed
> some more cases (though subtle) of improper teardown.
> 
> Especially in the case of failed tests, the simulator keeps alive (it's not
> destroyed), and this brought some trouble (of the segmentation fault at times)
> later on.
> 
> Also, many tests change NS3 configuration values, and they don't restore them
> to the usual defaults. Because of a lack of configuration getters, the patch
> attached only sets them back to the defaults documented in NS3's doxy, but the
> best thing would be to make backups of them and restore to their previous
> values.
> 
> In any case, this patch is a lot bigger, and it only fixes the tests for the
> case where you want to run several tests in succession, in the same process.
> ./waf check doesn't run tests this way, so there should be no difference there.
> 
> IF this patch is accepted, I can post the benchmarking stuff (without this
> patch, benchmark results aren't significant because of failed test runs).
Comment 4 Tom Henderson 2011-07-06 18:14:11 EDT
(In reply to comment #3)
> In the past, I was as frustrated as you by this and put together similar
> patches but I eventually gave up because I could not see how we could make sure
> that all our global variables are reset to the right state after a test runs.
> So, I thought: if I cannot get this right 100%, what is the point of making
> people believe it might work and suffer when it does not ? i.e., I chose to
> live with test.py (even though I hate this).
> 
> I would tend to feel like making this bug as WONTFIX based on the above unless
> you feel that you can really make the whole attribute system be nicely reset
> upon test completion to make sure different tests do not interfere on each
> other.

I was wondering whether config-store could be leveraged to save the initial state of defaults and reload it every new test.

Isn't this in general an issue of running multiple simulations from one main(); i.e. the same problem would be exhibited in programs like this one:
examples/wireless/wifi-adhoc.cc ?

Should we be advising people not to do this and to do multiple runs from outside of ns-3 main programs?
Comment 5 Mathieu Lacage 2011-07-06 19:11:33 EDT
(In reply to comment #4)
> (In reply to comment #3)
> > In the past, I was as frustrated as you by this and put together similar
> > patches but I eventually gave up because I could not see how we could make sure
> > that all our global variables are reset to the right state after a test runs.
> > So, I thought: if I cannot get this right 100%, what is the point of making
> > people believe it might work and suffer when it does not ? i.e., I chose to
> > live with test.py (even though I hate this).
> > 
> > I would tend to feel like making this bug as WONTFIX based on the above unless
> > you feel that you can really make the whole attribute system be nicely reset
> > upon test completion to make sure different tests do not interfere on each
> > other.
> 
> I was wondering whether config-store could be leveraged to save the initial
> state of defaults and reload it every new test.

yes. Some of our attributes are broken though. Say, some of the wifi attributes which have hidden dependencies between them which introduces ordering constraints on how you set them which breaks config-store badly. I have already pointed this out before. Someone needs to carefully review all attributes and check that they really are setters with no side-effects.

> Isn't this in general an issue of running multiple simulations from one main();
> i.e. the same problem would be exhibited in programs like this one:
> examples/wireless/wifi-adhoc.cc ?
> 
> Should we be advising people not to do this and to do multiple runs from
> outside of ns-3 main programs?

In general, it is less of a problem because users know the simulation they are running so they know how to cleanup. Here, we do not know which tests are being run so it is hard to protect against random crazy things beeing done there.
Comment 6 Claudio 2011-07-07 04:54:32 EDT
Ok, so, there are two possible venues:

A reset() method that really resets state, or config getters, so that tests can roll back changes.

Given the mentioned side effects, I'm leaning towards reset(), which would be broader.

Hm...
Comment 7 Mathieu Lacage 2011-07-07 04:56:59 EDT
(In reply to comment #6)
> Ok, so, there are two possible venues:
> 
> A reset() method that really resets state, or config getters, so that tests can
> roll back changes.
> 
> Given the mentioned side effects, I'm leaning towards reset(), which would be
> broader.
> 
> Hm...

Sure, the problem is "just" that you need to implement it. I tried a couple of times and did not get something reliable.
Comment 8 Claudio 2011-07-07 08:34:58 EDT
Ok, I did the reset thing, and it seems to work reliably.

The routing-aodv-regression test, especially the bug-772 one, seems to depend on config settings (arp timeout) set by previous test cases (which would be a problem).

I'll try to update the patch to include that.
Comment 9 Tom Henderson 2011-07-07 10:06:43 EDT
> > 
> > I was wondering whether config-store could be leveraged to save the initial
> > state of defaults and reload it every new test.
> 
> yes. Some of our attributes are broken though. Say, some of the wifi attributes
> which have hidden dependencies between them which introduces ordering
> constraints on how you set them which breaks config-store badly. I have already
> pointed this out before. Someone needs to carefully review all attributes and
> check that they really are setters with no side-effects.
> 

I file a new bug on this aspect (1213).

Otherwise, I support what Claudio is trying to do with this patch.
Comment 10 Claudio 2011-07-12 09:08:58 EDT
Ok, I found more sources of mis-isolation in tests, which could also be a real bug (ie, not only affect tests).

1. SeedManager::SetSeed(..) does not do anything if the RNG has been initialized already. This means, in some situations SetSeed could be ignored, which I guess is not good for experiments either.

2. Mac48Address has global state that cannot be controlled (ie: a static variable controlling the MAC sequence), so MACs assigned in PCAP-checking tests make tests fail when ran in succession. If I change the static by a GlobalValue, it gets fixed (thanks to the patch that resets GlobalValue s). Thing is, PCAPs need re-generation (MACs are still different than expected in current PCAPs, but consistent and reproducible).

Anybody knows how to generate new PCAPs?
Comment 11 Mitch Watrous 2011-07-12 16:16:37 EDT
Have you looked at the Tracing section of the ns-3 manual:

    www.nsnam.org/docs/release/3.11/manual/html/tracing.html
Comment 12 Claudio 2011-07-13 03:48:44 EDT
Ok, I know that, but I was expecting something along the lines of "Run test-runner with arguments blah". Someone already does generate them from time to time, so there must be a rather easy way to do it...

...it's just not documented.
Comment 13 Claudio 2011-07-13 10:58:08 EDT
NM - I just found it.

I'm preparing a patchset.

Since it will take time (I have to test each patchset applied to the current tip), a summary first:
 * SeedManager::SetSeed/SetRun did not take effect after RNG initialization
   - incidentally, after forcing it to re-seed the RNG, 
     creating RandomVariables isn't as fast (though not that slow either), 
     so I have a patch that makes simple-odfm-wimax-phy NOT create an RNG 
     each time a packet is processed.
 * PacketMetadata: it has Enable() but no Disable(). So a Disable was added
   that the test framework can use to make sure there are no side effects 
   after test execution
 * Config::Reset() added that resets all GlobalValue s and attribute defaults
   to their initial values.
 * Mac48Address uses a static local variable to generate the MAC series,
   this results in uncontrollable side effects that make tests that depend
   on MACs not repeatable. Changing it to a GlobalValue (that gets updated
   after each call to Allocate) solves this, allowing user code control
   over the MAC series (through Config), and allowing the test framework
   to reset the series before test runs.
 * The test framework now assures repeatable conditions within test cases, by:
   - Destroying the simulator at base TestCase::DoTeardown/Setup
   - Resetting configuration (attribute defaults and global values) at
     various points (TestCase::DoTeardown, TestSuite::DoSetup)
   - Saving/Restoring the RNG state at TestSuite::DoSetup/Teardown
     (I tried per TestCase, but some test cases depend on RNG state
     set by previous test cases, sorting that out would have been
     a LOT more work)
 * I recreated the PCAP traces that now use repeatable (different)
   MACs and RNG state.

Incidentally, I found that RvBatteryModel segfaults in some situations when running tests repeatedly. I'll post a patch in a separate issue (since it's completely independent with the issue at hand here).
Comment 14 Claudio 2011-07-13 12:34:14 EDT
Created attachment 1200 [details]
Patchset with SeedManager::SetSeed/Run fixes

Import with "hg import <patchfile>"
Requires PCAP re-generation.
Comment 15 Claudio 2011-07-13 12:37:30 EDT
Created attachment 1201 [details]
Patchset with Config::Reset implementation

Import with "hg import <patchfile>"
Comment 16 Claudio 2011-07-13 12:38:14 EDT
Created attachment 1202 [details]
Patchset with complete set of test repeatability fixes

Import with "hg import <patchfile>"
Requires PCAP re-generation.
Comment 17 Claudio 2011-07-13 12:38:54 EDT
Created attachment 1203 [details]
Updated reference PCAP traces for tests
Comment 18 Tom Henderson 2011-07-29 12:42:14 EDT
(In reply to comment #13)

>  * The test framework now assures repeatable conditions within test cases, by:
>    - Destroying the simulator at base TestCase::DoTeardown/Setup
>    - Resetting configuration (attribute defaults and global values) at
>      various points (TestCase::DoTeardown, TestSuite::DoSetup)
>    - Saving/Restoring the RNG state at TestSuite::DoSetup/Teardown
>      (I tried per TestCase, but some test cases depend on RNG state
>      set by previous test cases, sorting that out would have been
>      a LOT more work)

I like the principle of this; for how the current test framework runs tests sequentially, it seems like this is the best workaround we have.

One small concern that I have is that the values restored in TestCase::DoTeardown may be hard to maintain, in case the upstream default values change.  I'm wondering whether a safer approach would be to just cache the current defaults when in DoSetup state so that they can be restored in DoTeardown.  

Conceptually, what I mean is that you would do something like this in TestCase::DoSetup:

  SaveDefault ("ns3::WifiRemoteStationManager::FragmentationThreshold");
before doing
  Config::SetDefault (...);

then in TestCase::DoTeardown, you would do

  RestoreDefault ("ns3::WifiRemoteStationManager::FragmentationThreshold");

BTW, thanks for doing all of this cleanup; I'd like to get these patches in.
Comment 19 Claudio 2011-08-01 04:02:16 EDT
(In reply to comment #18)
> One small concern that I have is that the values restored in
> TestCase::DoTeardown may be hard to maintain, in case the upstream default
> values change.  I'm wondering whether a safer approach would be to just cache
> the current defaults when in DoSetup state so that they can be restored in
> DoTeardown.  

That's exactly what the last patch does.

> TestCase::DoSetup:
> 
>   SaveDefault ("ns3::WifiRemoteStationManager::FragmentationThreshold");
> before doing
>   Config::SetDefault (...);

It's not explicit, every GlobalValue remembers the initial default given at construction time. They have a Reset() method that can be called, or a convenient Config::Reset() that resets it all. TestCase::DoTeardown calls Config::Reset to clean all up.

> BTW, thanks for doing all of this cleanup; I'd like to get these patches in.

:-)

You're welcome.
Comment 20 Tom Henderson 2011-08-01 09:23:15 EDT
(In reply to comment #19)
> (In reply to comment #18)
> > One small concern that I have is that the values restored in
> > TestCase::DoTeardown may be hard to maintain, in case the upstream default
> > values change.  I'm wondering whether a safer approach would be to just cache
> > the current defaults when in DoSetup state so that they can be restored in
> > DoTeardown.  
> 
> That's exactly what the last patch does.

I was looking at this part of the patch (for example):
https://www.nsnam.org/bugzilla/attachment.cgi?id=1202&action=diff#a/src/energy/test/basic-energy-model-test.cc_sec3

maybe the current patch doesn't uniformly apply Config::Reset()?  (I see it elsewhere in the patch, though)
Comment 21 Claudio 2011-08-01 09:31:31 EDT
(In reply to comment #20)
> I was looking at this part of the patch (for example):
> https://www.nsnam.org/bugzilla/attachment.cgi?id=1202&action=diff#a/src/energy/test/basic-energy-model-test.cc_sec3
> 
> maybe the current patch doesn't uniformly apply Config::Reset()?  (I see it
> elsewhere in the patch, though)

Oh... my bad...

...those SetDefault at TearDown should no longer be necessary. I though I had removed them.

TestCase::DoTeardown() calls Config::Reset() already (in a previous patch), so SetDefault should not be necessary.
Comment 22 Claudio 2011-08-04 05:04:24 EDT
Created attachment 1217 [details]
Monolithic patch

Attached a monolithic patch as per Matthew's request.

It has NOT been rebased to the development head, too many test changes there, merging could take a while.