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

bad detecting test when using super class #961

Closed
jscotka opened this issue Jan 15, 2016 · 14 comments
Closed

bad detecting test when using super class #961

jscotka opened this issue Jan 15, 2016 · 14 comments

Comments

@jscotka
Copy link

jscotka commented Jan 15, 2016

Hi,
I had similar code like:

#!/usr/bin/python

from avocado import Test
from avocado import main

class SuperTest(Test):
    def xxx(self):
        print "ahoj"

class BasicTestSuite(SuperTest):

    def test1(self):
        self.xxx()
        self.assertTrue(True)

if __name__ == "__main__":
    main()

This code caused, that avocado dont find that it is test.
I would like to use some generic funcions in other class, so I expected that inheritance works intuitively.

$ avocado run ./test.py
Unable to discover url(s) './test.py' with loader plugins(s) 'file', 'external', try running 'avocado list -V ./test.py' to see the details.

In case super class is in separate file (what was my case)
"avocado run" is in unghly cycle, and probably will kill machine, because of memory exhaustion:
like:

[stdout] [stdout] [stdout] Avocado version: 0.29.0
[stdout] [stdout] Avocado version: 0.29.0
[stdout] [stdout] Avocado version: 0.29.0
[stdout] Avocado version: 0.29.0
[stdout] [stdout] Avocado version: 0.29.0
[stdout] Avocado version: 0.29.0
[stdout] Avocado version: 0.29.0
Avocado version: 0.29.0

try this test (splitted to two files)

test.py:

#!/usr/bin/python

from avocado import Test
from avocado import main
from test2 import *

class BasicTestSuite(SuperTest):

    def test1(self):
        self.xxx()
        self.assertTrue(True)

if __name__ == '__main__':
    main()

and test2.py:

#!/usr/bin/python

from avocado import Test

class SuperTest(Test):
    def xxx(self):
        print "ahoj"

finally I had to solve by workaound, that I have multiple inheritance in testing class like: ( class BasicTestsuite(Test,SuperTest), but I expected that direct inheritance will work well.
And also this does not allow me to use setUp and tearDown methods in SuperTest class, But I have to explicitly register them in BasicTestsuite class.

@clebergnu
Copy link
Contributor

For those cases you can use the ":avocado: enable" tag in the class
docstring.

It's documented at:

http://avocado-framework.readthedocs.org/en/latest/WritingTests.html#test-tags
On Jan 15, 2016 5:36 AM, "jscotka" notifications@github.com wrote:

Hi,
I had similar code like:

#!/usr/bin/python

from avocado import Test
from avocado import main

class SuperTest(Test):
def xxx(self):
print "ahoj"

class BasicTestSuite(SuperTest):

def test1(self):
    selfxxx()
    selfassertTrue(True)

if name == 'main':
main()
'''

This code caused, that avocado dont find that it is test
I would like to use some generic funcions in other class, so I expected that inheritance works intuitively
$ avocado run /testpy
Unable to discover url(s) '/testpy' with loader plugins(s) 'file', 'external', try running 'avocado list -V /testpy' to see the details

In case super class is in separate file (what was my case)
"avocado run" is in unghly cycle, and probably will kill machine, because of memory exhaustion:
like:

[stdout] [stdout] [stdout] Avocado version: 0290
[stdout] [stdout] Avocado version: 0290
[stdout] [stdout] Avocado version: 0290
[stdout] Avocado version: 0290
[stdout] [stdout] Avocado version: 0290
[stdout] Avocado version: 0290
[stdout] Avocado version: 0290
Avocado version: 0290
'''

try this test (splitted to two files)
testpy:

#!/usr/bin/python

from avocado import Test
from avocado import main
from test2 import *

class BasicTestSuite(SuperTest):

def test1(self):
    selfxxx()
    selfassertTrue(True)

if name == 'main':
main()
'''

and test2py:

#!/usr/bin/python

from avocado import Test

class SuperTest(Test):
def xxx(self):
print "ahoj"
'''

finally I had to solve by workaound, that I have multiple inheritance in
testing class like: ( class BasicTestsuite(Test,SuperTest), but I expected
that direct inheritance will work well
And also this does not allow me to use setUp and tearDown methods in
SuperTest class, But I have to explicitly register them in BasicTestsuite
class


Reply to this email directly or view it on GitHub
#961.

@jscotka
Copy link
Author

jscotka commented Jan 15, 2016

thanks for response.
Yep, this is good way, it is not so intuitive but it is documented.
So maybe second trouble is bug and should be resoved causing infinite loop in this bad case. It should detect it and stop infinite loop until system crash out of memory.

@clebergnu
Copy link
Contributor

@jscotka I'll try to reproduce the scenario you're reporting.

@jscotka
Copy link
Author

jscotka commented Jan 15, 2016

should be easy. Just to have second scenario with separated classes to two files and then:
$ avocado run ./test.py
then you have to interupte it after while because infinite loop:
JOB ID : 8da27c4511f2b3fccd8819edc018ac692e0a31dd
JOB LOG : /home/jscotka/avocado/job-results/job-2016-01-15T14.17-8da27c4/job.log
TESTS : 1
(1/1) ./test.py: ^C
Interrupt requested. Waiting 2 seconds for test to finish (ignoring new Ctrl+C until then)
^CKilling test subprocess 25920

ERROR (157.27 s)
RESULTS : PASS 0 | ERROR 1 | FAIL 0 | SKIP 0 | WARN 0 | INTERRUPT 0
JOB HTML : /home/jscotka/avocado/job-results/job-2016-01-15T14.17-8da27c4/html/results.html
TIME : 157.27 s

I'm unable to upload result log beause It has 48M :-)
I had to cut it to 5M
cutted.txt

@apahim
Copy link
Contributor

apahim commented Jan 18, 2016

Started looking into this, I'm not able to reproduce::

[apahim@hurricane ~]$ cat test.py
#!/usr/bin/python

from avocado import Test
from avocado import main
from test2 import *

class BasicTestSuite(SuperTest):
    """
    :avocado: enable
    """
    def test1(self):
        self.xxx()
        self.assertTrue(True)

if __name__ == '__main__':
    main()

[apahim@hurricane ~]$ cat test2.py
#!/usr/bin/python

from avocado import Test

class SuperTest(Test):
    def xxx(self):
        print "ahoj"

[apahim@hurricane ~]$ avocado run ./test.py
JOB ID     : 56f1f29987d63df2ca4a63edef9a96e07cebb367
JOB LOG    : /home/apahim/avocado/job-results/job-2016-01-18T15.12-56f1f29/job.log
TESTS      : 1
 (1/1) ./test.py:BasicTestSuite.test1: PASS (0.00 s)
RESULTS    : PASS 1 | ERROR 0 | FAIL 0 | SKIP 0 | WARN 0 | INTERRUPT 0
JOB HTML   : /home/apahim/avocado/job-results/job-2016-01-18T15.12-56f1f29/html/results.html
TIME       : 0.00 s
[apahim@hurricane ~]$

Any thoughts on that?

@clebergnu
Copy link
Contributor

Now I'm baffled. I did hit that issue and now I can't reproduce it. Let me try to bisect it.

@clebergnu
Copy link
Contributor

OK, now I remember how I hit it: you have to $ chmod +x test.py. Then avocado considers test.py a simple test:

$ avocado list -V ./test.py

Type   Test
SIMPLE ./test.py

ACCESS_DENIED: 0
BROKEN_SYMLINK: 0
EXTERNAL: 0
FILTERED: 0
INSTRUMENTED: 0
MISSING: 0
NOT_A_TEST: 0
SIMPLE: 1
VT: 0

And then our very own fork bomb works!

@clebergnu
Copy link
Contributor

So, having the docstring tag (:avocado: enable) prevents this bug because the test on test.py is considered INSTRUMENTED. Still a bug though.

@clebergnu
Copy link
Contributor

@apahim I've written a reproducer to that bug as a functional test:

https://github.com/clebergnu/avocado/tree/simple_tests_fork_bomb

clebergnu@744e261

@clebergnu
Copy link
Contributor

So, I actually found what is causing this, and it has very little to do with the loader.

What happens is, when a test like this is run as a simple test, it basically runs in standalone mode. When it runs in standalone mode (from avocado import main; main()), it creates a new Job(), and tells the job to run sys.argv[0] as a test.

Then, quite obviously the loader of that new job will look at sys.argv[0] and detect it as a simple test. Then it'll run in standalone mode and the loop never ends.

@ldoktor
Copy link
Contributor

ldoktor commented Jan 19, 2016

yep, it's what user asked for...

apahim added a commit to apahim/avocado that referenced this issue Jan 19, 2016
apahim added a commit to apahim/avocado that referenced this issue Jan 19, 2016
@clebergnu
Copy link
Contributor

@ldoktor replying to your last comment: do you think we should step back and leave main() as is? So far, I stand behind my original idea that main() is broken, pretty much not related to the loader. Example:

#!/usr/bin/python

from avocado import main

if __name__ == '__main__':
    main()

Make this an executable, and run it (standalone). No tests, but still generates a fork bomb.

@ldoktor
Copy link
Contributor

ldoktor commented Jan 22, 2016

Well how about this approach. This code can be put into files to execute the file as avocado tests (INSTRUMENTED). How about tuning the options in the main to enable only file.INSTRUMENTED tests? Even avocado-virt tests are INSTRUMENTED. That should prevent the fork bomb...

Btw my first idea was to disable file.SIMPLE loader, but that might be quite hard to do with the current structure...

clebergnu added a commit to clebergnu/avocado that referenced this issue Jan 24, 2016
Because the current implementation of avocado.main() creates a job
and runs "sys.argv[0]" to implement standalone mode, it ends up
running itself over and over.

This simple proposed fix, prevents avocado.main() from running
itself again if called from itself. Since they are on different
processes, the mechanism chosen to do this is to set an environment
variable, that will be seen by the next process.

This adresses issue avocado-framework#961.

Signed-off-by: Cleber Rosa <crosa@redhat.com>
clebergnu added a commit to clebergnu/avocado that referenced this issue Jan 25, 2016
Because the current implementation of avocado.main() creates a job
and runs "sys.argv[0]" to implement standalone mode, it ends up
running itself over and over.

This simple proposed fix, prevents avocado.main() from running
itself again if called from itself. Since they are on different
processes, the mechanism chosen to do this is to set an environment
variable, that will be seen by the next process.

This adresses issue avocado-framework#961.

Signed-off-by: Cleber Rosa <crosa@redhat.com>
clebergnu added a commit to clebergnu/avocado that referenced this issue Jan 27, 2016
Because the current implementation of avocado.main() creates a job
and runs "sys.argv[0]" to implement standalone mode, it ends up
running itself over and over.

This simple proposed fix, prevents avocado.main() from running
itself again if called from itself. Since they are on different
processes, the mechanism chosen to do this is to set an environment
variable, that will be seen by the next process.

Also, by exiting from main() with an error code, the test first
level test will fail. This will let the user know that the chosen
approach (SIMPLE tests written in Python and calling main()) are
not worthy of a PASS.

This adresses issue avocado-framework#961.

Signed-off-by: Cleber Rosa <crosa@redhat.com>
clebergnu added a commit to clebergnu/avocado that referenced this issue Jan 27, 2016
Because the current implementation of avocado.main() creates a job
and runs "sys.argv[0]" to implement standalone mode, it ends up
running itself over and over.

This simple proposed fix, prevents avocado.main() from running
itself again if called from itself. Since they are on different
processes, the mechanism chosen to do this is to set an environment
variable, that will be seen by the next process.

Also, by exiting from main() with an error code, the test first
level test will fail. This will let the user know that the chosen
approach (SIMPLE tests written in Python and calling main()) are
not worthy of a PASS.

This adresses issue avocado-framework#961.

Signed-off-by: Cleber Rosa <crosa@redhat.com>
clebergnu added a commit to clebergnu/avocado that referenced this issue Jan 28, 2016
Because the current implementation of avocado.main() creates a job
and runs "sys.argv[0]" to implement standalone mode, it ends up
running itself over and over.

This simple proposed fix, prevents avocado.main() from running
itself again if called from itself. Since they are on different
processes, the mechanism chosen to do this is to set an environment
variable, that will be seen by the next process.

Also, by exiting from main() with an error code, the test first
level test will fail. This will let the user know that the chosen
approach (SIMPLE tests written in Python and calling main()) are
not worthy of a PASS.

The functional tests make use of Python's standard library utilities
(subprocess module) directly for running Avocado because of current
issues with Avocado's own process utility module.

This adresses issue avocado-framework#961.

Signed-off-by: Cleber Rosa <crosa@redhat.com>
@clebergnu
Copy link
Contributor

@jscotka this should now be fixed as per #991

If you find any other issues, please let us know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants