Wednesday, October 29, 2008

nosetests who? Or : how winPDB p0wnz us all...

Victoly!!!
Hell yes!
It took almost three weeks, but in the end it was worth it.
You see, nosetest has a small problem with plugins. How did I get to that conclusion?
Well, after finding out that nosetests actually is not only an executable but a library that can be invoked by python code as well (!), and after having found an awesome windows - python debugger : winPDB, a simple debugger with the power of python. You can imagine what comes out of it.

So I made a small python script that includes the nose module (nosetests.py) :
import nose
run()
Complicated, huh?
This small snipped executes nose with the commandline that I passed to the script.
So once this was done, I could run it in winPDB with a commandline like this:

winpdb nosetests.py --sysloghost=localhost --with-nosexunit --xml-report-folder=c:\test test_mytest.py

This opens up the winpdb debugger. After some tracing, I found what I was looking for:
in the run method of the TextTestRunner class, the plugins are finalized with the following call: self.config.plugins.finalize(result), forelast line of the method. The call redirects to the various plugin finalization methods. The plugin we are using is handled by the standard plugin manager, PluginManager. In short, the finalize method redirects the call to a simple method, which processes the finalization of the plugins until one of those finalizations returns a value.
Our homegrown syslog plugin passed the received result on to the nosexunit manager, which of course was not null.
Nonenthless to say, the nosexunit plugin was always executed after the syslogplugin. Forcing the syslog plugin finalization method to return null resolved the problem. Turns out that because of the plugin finalization manager executing first the finalization of the syslog plugin the nosexunit finalization was not executed, thus the output was not produced. I wonder if this is a bug?

Now, I don't know the following things:

  1. How nosetests handles plugin loading / unloading with priority if it handles finalization with priority at all
  2. If it was a good idea to forcingly set the result to "None" in our syslog utility finalization's method.
Considering the fact that the method in this case is executed as a final one, probably point 2) is not very relevant. But how does nosetests actually handle plugin priorities? Seems like it assigns to each of them a score, which is then used to decide which one gets loaded first and so on.
Look what I found crawling through google :
- Added score property to plugins to allow plugins to execute in a
defined order (higher score execute first).
This comes from the changelog of version 0.10.0a1. So it seems the problem is not totally new (damnit!). So it seems our search is not over.

2 comments:

Roman Plášil said...

you need nose.run() in your complicated script ;)

Tone Kastlunger said...

Ah you mean in my crappy syslog plugin?