Message ID | 1460633543-7366-1-git-send-email-silbe@linux.vnet.ibm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 14.04.2016 13:32, Sascha Silbe wrote: > Running an iotests-based Python test directly might appear to work, > but may fail in subtle ways and is insecure: > > - It creates files with predictable file names in a world-writable > location (/var/tmp). > > - Tests expect the environment to be set up by check. E.g. 041 and 055 > may take the wrong code paths if QEMU_DEFAULT_MACHINE is not > set. This can lead to false negatives. > > Instead fail hard and tell the user we want to be run via "check". > > Signed-off-by: Sascha Silbe <silbe@linux.vnet.ibm.com> > Reviewed-by: Bo Tu <tubo@linux.vnet.ibm.com> > --- > It's possible to fix iotests.py to work even outside of check, but > that requires reimplementing parts of what check currently does. I'd > prefer not to do that this late in the cycle. > > It would be nice to have this in 2.6, just in case someone even tries > running a Python-based test directly instead of using ./check like for > the shell-based tests. But it's not crucial. > --- > tests/qemu-iotests/iotests.py | 6 +++++- > 1 file changed, 5 insertions(+), 1 deletion(-) > > diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py > index 0c0b533..8c7138f 100644 > --- a/tests/qemu-iotests/iotests.py > +++ b/tests/qemu-iotests/iotests.py > @@ -46,7 +46,7 @@ if os.environ.get('QEMU_OPTIONS'): > > imgfmt = os.environ.get('IMGFMT', 'raw') > imgproto = os.environ.get('IMGPROTO', 'file') > -test_dir = os.environ.get('TEST_DIR', '/var/tmp') > +test_dir = os.environ.get('TEST_DIR') > output_dir = os.environ.get('OUTPUT_DIR', '.') > cachemode = os.environ.get('CACHEMODE') > qemu_default_machine = os.environ.get('QEMU_DEFAULT_MACHINE') > @@ -441,6 +441,10 @@ def verify_quorum(): > def main(supported_fmts=[], supported_oses=['linux']): > '''Run tests''' > > + if test_dir is None or qemu_default_machine is None: I think checking test_dir would have been sufficient; this makes it look like it might want to be a complete list of variables that have to be set, but then "cachemode" is missing. > + sys.stderr.write('Please run this test via ./check\n') Or not ./, for people who have separate build and source trees, you don't want to invoke check in the source tree. ;-) I'm not sure whether I'd want a v2 just because of this. It's bike-shedding, but now that I think about it I guess I think I do. So would you be so kind as to replace the "./check" by "the check script"? :-) (I don't particularly care about whether you change the condition used in the if statement, though.) Max > + sys.exit(os.EX_USAGE) > + > debug = '-d' in sys.argv > verbosity = 1 > verify_image_format(supported_fmts) >
Sascha Silbe <silbe@linux.vnet.ibm.com> writes: > Running an iotests-based Python test directly might appear to work, > but may fail in subtle ways and is insecure: > > - It creates files with predictable file names in a world-writable > location (/var/tmp). > > - Tests expect the environment to be set up by check. E.g. 041 and 055 > may take the wrong code paths if QEMU_DEFAULT_MACHINE is not > set. This can lead to false negatives. > > Instead fail hard and tell the user we want to be run via "check". Are the problems serious enough to warrant rejecting the attempt to run the tests directly outright? Judging from your description, I'm inclined to "no". > Signed-off-by: Sascha Silbe <silbe@linux.vnet.ibm.com> > Reviewed-by: Bo Tu <tubo@linux.vnet.ibm.com> > --- > It's possible to fix iotests.py to work even outside of check, but > that requires reimplementing parts of what check currently does. I'd > prefer not to do that this late in the cycle. > > It would be nice to have this in 2.6, just in case someone even tries > running a Python-based test directly instead of using ./check like for > the shell-based tests. But it's not crucial. > --- > tests/qemu-iotests/iotests.py | 6 +++++- > 1 file changed, 5 insertions(+), 1 deletion(-) > > diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py > index 0c0b533..8c7138f 100644 > --- a/tests/qemu-iotests/iotests.py > +++ b/tests/qemu-iotests/iotests.py > @@ -46,7 +46,7 @@ if os.environ.get('QEMU_OPTIONS'): > > imgfmt = os.environ.get('IMGFMT', 'raw') > imgproto = os.environ.get('IMGPROTO', 'file') > -test_dir = os.environ.get('TEST_DIR', '/var/tmp') > +test_dir = os.environ.get('TEST_DIR') > output_dir = os.environ.get('OUTPUT_DIR', '.') > cachemode = os.environ.get('CACHEMODE') > qemu_default_machine = os.environ.get('QEMU_DEFAULT_MACHINE') > @@ -441,6 +441,10 @@ def verify_quorum(): > def main(supported_fmts=[], supported_oses=['linux']): > '''Run tests''' > > + if test_dir is None or qemu_default_machine is None: > + sys.stderr.write('Please run this test via ./check\n') > + sys.exit(os.EX_USAGE) > + > debug = '-d' in sys.argv > verbosity = 1 > verify_image_format(supported_fmts) Aha, you're not actually rejecting the attempt to run the tests directly, you're merely requiring two environment variables. That's okay with me. However, the commit message should explain it. I'd also rephrase the error message to something like <program_name>: TEST_DIR and QEMU_DEFAULT_MACHINE must be set in environment The easiest way to do that is running the test via the check script.
Dear Markus, Markus Armbruster <armbru@redhat.com> writes: >> Running an iotests-based Python test directly might appear to work, >> but may fail in subtle ways and is insecure: >> >> - It creates files with predictable file names in a world-writable >> location (/var/tmp). >> >> - Tests expect the environment to be set up by check. E.g. 041 and 055 >> may take the wrong code paths if QEMU_DEFAULT_MACHINE is not >> set. This can lead to false negatives. >> >> Instead fail hard and tell the user we want to be run via "check". > > Are the problems serious enough to warrant rejecting the attempt to run > the tests directly outright? > > Judging from your description, I'm inclined to "no". Having tests do unexpected things and / or fail silently is "serious" in my book. After all, what's the value of tests if they don't yell when something is broken? [tests/qemu-iotests/iotests.py] [...] >> + if test_dir is None or qemu_default_machine is None: >> + sys.stderr.write('Please run this test via ./check\n') >> + sys.exit(os.EX_USAGE) >> + > > Aha, you're not actually rejecting the attempt to run the tests > directly, you're merely requiring two environment variables. That's > okay with me. [...] I should probably add a comment that these two environment variables are merely used as proxies that indicate we haven't been run via "check". They are the ones where there isn't any useful default value we could fall back, but without a full audit we can't tell what else some of the tests may expect that would normally be set up by "check" (or at least I can't). Sascha
Dear Max, Max Reitz <mreitz@redhat.com> writes: > On 14.04.2016 13:32, Sascha Silbe wrote: [tests/qemu-iotests/iotests.py] [...] >> def main(supported_fmts=[], supported_oses=['linux']): >> '''Run tests''' >> >> + if test_dir is None or qemu_default_machine is None: > > I think checking test_dir would have been sufficient; this makes it look > like it might want to be a complete list of variables that have to be > set, but then "cachemode" is missing. Markus Armbruster basically pointed out the same issue, so how about this version: # We are using TEST_DIR and QEMU_DEFAULT_MACHINE as proxies to # indicate that we're not being run via "check". There may be # other things set up by "check" that individual test cases rely # on. if test_dir is None or qemu_default_machine is None: sys.stderr.write('Please run this test via the "check" script\n') sys.exit(os.EX_USAGE) >> + sys.stderr.write('Please run this test via ./check\n') > > Or not ./, for people who have separate build and source trees, you > don't want to invoke check in the source tree. ;-) Yeah, was thinking about that, but ultimately considered ./check to be the best indication of a) "check" being the name of a script and b) residing in the same directory as the test. But I don't care much about this, so see the above version. Sascha
Sascha Silbe <silbe@linux.vnet.ibm.com> writes: > Dear Markus, > > Markus Armbruster <armbru@redhat.com> writes: > >>> Running an iotests-based Python test directly might appear to work, >>> but may fail in subtle ways and is insecure: >>> >>> - It creates files with predictable file names in a world-writable >>> location (/var/tmp). >>> >>> - Tests expect the environment to be set up by check. E.g. 041 and 055 >>> may take the wrong code paths if QEMU_DEFAULT_MACHINE is not >>> set. This can lead to false negatives. >>> >>> Instead fail hard and tell the user we want to be run via "check". >> >> Are the problems serious enough to warrant rejecting the attempt to run >> the tests directly outright? >> >> Judging from your description, I'm inclined to "no". > > Having tests do unexpected things and / or fail silently is "serious" in > my book. After all, what's the value of tests if they don't yell when > something is broken? > > > [tests/qemu-iotests/iotests.py] > [...] >>> + if test_dir is None or qemu_default_machine is None: >>> + sys.stderr.write('Please run this test via ./check\n') >>> + sys.exit(os.EX_USAGE) >>> + >> >> Aha, you're not actually rejecting the attempt to run the tests >> directly, you're merely requiring two environment variables. That's >> okay with me. [...] > > I should probably add a comment that these two environment variables are > merely used as proxies that indicate we haven't been run via > "check". They are the ones where there isn't any useful default value we > could fall back, but without a full audit we can't tell what else some > of the tests may expect that would normally be set up by "check" (or at > least I can't). Say you had an accurate way to find out whether we're running under "check". You could then reject any attempt to run the test directly. I'd oppose that. It's okay to have test wrapper scripts to configure the tests just so. It's okay to tell people to use them. But "you can't do that, Dave" is not okay. It's okay to require certain environment variables to be set. That's what your patch does (but your commit message doesn't quite say). It would not be okay to interfere with my ability to run tests the way *I* want. If a test breaks when I run it my way, I get to keep the pieces.
Dear Markus, Markus Armbruster <armbru@redhat.com> writes: > Say you had an accurate way to find out whether we're running under > "check". You could then reject any attempt to run the test directly. > I'd oppose that. > > It's okay to have test wrapper scripts to configure the tests just so. > It's okay to tell people to use them. But "you can't do that, Dave" is > not okay. [...] AFAICT the environment in which the individual test cases run isn't well-defined. Currently it's indirectly defined by whatever "check" does. The goal of the patch is to catch unwary developers invoking the tests directly from the command line, providing them with useful advice. If somebody wants to write another test runner (in place of "check"), it's their responsibility to set up the environment appropriately. (They could even set an environment variable "I_AM_CHECK=yes" if that's part of the environment the tests expect). I'd be perfectly fine with defining the environment more clearly and possibly extending the implementation to allow individual test cases to be invoked directly (without a test runner like "check"). But that would be 2.7 material. Sascha
On 19.04.2016 14:22, Sascha Silbe wrote: > Dear Max, > > Max Reitz <mreitz@redhat.com> writes: > >> On 14.04.2016 13:32, Sascha Silbe wrote: > [tests/qemu-iotests/iotests.py] > [...] >>> def main(supported_fmts=[], supported_oses=['linux']): >>> '''Run tests''' >>> >>> + if test_dir is None or qemu_default_machine is None: >> >> I think checking test_dir would have been sufficient; this makes it look >> like it might want to be a complete list of variables that have to be >> set, but then "cachemode" is missing. > > Markus Armbruster basically pointed out the same issue, so how about > this version: > > # We are using TEST_DIR and QEMU_DEFAULT_MACHINE as proxies to > # indicate that we're not being run via "check". There may be > # other things set up by "check" that individual test cases rely > # on. > if test_dir is None or qemu_default_machine is None: > sys.stderr.write('Please run this test via the "check" script\n') > sys.exit(os.EX_USAGE) I'm OK with that. I can imagine Markus isn't, because it's implying that you should only run this test through "check", whereas Markus says that maybe you have your own script and that is fine, too. I think two things: 1. I'm not sure why you would want your own script. If the check script isn't good enough, extend it. 2. If you do want your own script, I guess setting up the necessary environment for each test is complicated enough to require you to know what you're doing. And if you know what you're doing, you won't really care about the wording of this warning anyway. I think this is just a warning for unwary users who just try to execute a python test directly because they think that maybe they can. And then this line is just telling them that no, that is not how the test is supposed to be run; instead, it tells them the most convenient and common way to run it. I think it would be confusing if we printed the exact technical details here which basically nobody cares about anyway. So I'm completely fine with this version. >>> + sys.stderr.write('Please run this test via ./check\n') >> >> Or not ./, for people who have separate build and source trees, you >> don't want to invoke check in the source tree. ;-) > > Yeah, was thinking about that, but ultimately considered ./check to be > the best indication of a) "check" being the name of a script and b) > residing in the same directory as the test. But I don't care much about > this, so see the above version. Yes, that looks fine to me. Regarding b): If you separate the build tree from the source tree, you have to run the check script from the build tree. During the build process, qemu will in fact automatically create a symlink in the build tree. Therefore, in that case, you don't want to execute "./check" in the same directory as the test is in. Max
Dear Max, Max Reitz <mreitz@redhat.com> writes: > On 19.04.2016 14:22, Sascha Silbe wrote: [...] >> # We are using TEST_DIR and QEMU_DEFAULT_MACHINE as proxies to >> # indicate that we're not being run via "check". There may be >> # other things set up by "check" that individual test cases rely >> # on. >> if test_dir is None or qemu_default_machine is None: >> sys.stderr.write('Please run this test via the "check" script\n') >> sys.exit(os.EX_USAGE) > > I'm OK with that. I can imagine Markus isn't, because it's implying that > you should only run this test through "check", whereas Markus says that > maybe you have your own script and that is fine, too. [...] > 2. If you do want your own script, I guess setting up the necessary > environment for each test is complicated enough to require you to know > what you're doing. And if you know what you're doing, you won't really > care about the wording of this warning anyway. > > I think this is just a warning for unwary users who just try to execute > a python test directly because they think that maybe they can. [...] Seems we're on the same page. For those who want to write their own test runners, the comment in the source indicates why we recommend running via "check", implying that they'd need to set up the environment just like "check" does. That's more or less the best we can do in the current situation, so I'll spin up a v2 with the above code block. If Markus would like it explicitly spelled out in the comment or the error message, that'd be fine with me, too. Feel free to amend locally before merging in that case. [...] > Regarding b): If you separate the build tree from the source tree, you > have to run the check script from the build tree. During the build > process, qemu will in fact automatically create a symlink in the build > tree. Therefore, in that case, you don't want to execute "./check" in > the same directory as the test is in. Whereas there probably are no symlinks to the individual test cases. Good point. Sascha
Max Reitz <mreitz@redhat.com> writes: > On 19.04.2016 14:22, Sascha Silbe wrote: >> Dear Max, >> >> Max Reitz <mreitz@redhat.com> writes: >> >>> On 14.04.2016 13:32, Sascha Silbe wrote: >> [tests/qemu-iotests/iotests.py] >> [...] >>>> def main(supported_fmts=[], supported_oses=['linux']): >>>> '''Run tests''' >>>> >>>> + if test_dir is None or qemu_default_machine is None: >>> >>> I think checking test_dir would have been sufficient; this makes it look >>> like it might want to be a complete list of variables that have to be >>> set, but then "cachemode" is missing. >> >> Markus Armbruster basically pointed out the same issue, so how about >> this version: >> >> # We are using TEST_DIR and QEMU_DEFAULT_MACHINE as proxies to >> # indicate that we're not being run via "check". There may be >> # other things set up by "check" that individual test cases rely >> # on. >> if test_dir is None or qemu_default_machine is None: >> sys.stderr.write('Please run this test via the "check" script\n') >> sys.exit(os.EX_USAGE) > > I'm OK with that. I can imagine Markus isn't, because it's implying that > you should only run this test through "check", whereas Markus says that > maybe you have your own script and that is fine, too. > > I think two things: > > 1. I'm not sure why you would want your own script. If the check script > isn't good enough, extend it. > > 2. If you do want your own script, I guess setting up the necessary > environment for each test is complicated enough to require you to know > what you're doing. And if you know what you're doing, you won't really > care about the wording of this warning anyway. > > I think this is just a warning for unwary users who just try to execute > a python test directly because they think that maybe they can. And then > this line is just telling them that no, that is not how the test is > supposed to be run; instead, it tells them the most convenient and > common way to run it. > > I think it would be confusing if we printed the exact technical details > here which basically nobody cares about anyway. > > So I'm completely fine with this version. As Max predicted, I'm not :) 'Please run this test via the "check" script' isn't an error message, it's advice. Advice is appreciated, but an error message must come first. I reiterate my proposal to use something like <program_name>: TEST_DIR and QEMU_DEFAULT_MACHINE must be set in environment The easiest way to do that is running the test via the check script. or <program_name>: TEST_DIR and QEMU_DEFAULT_MACHINE must be set in environment Please run this test via the "check" script [...]
Dear Markus, Markus Armbruster <armbru@redhat.com> writes: > 'Please run this test via the "check" script' isn't an error message, > it's advice. Advice is appreciated, but an error message must come > first. I reiterate my proposal to use something like > > <program_name>: TEST_DIR and QEMU_DEFAULT_MACHINE must be set in environment > The easiest way to do that is running the test via the check script. But I don't know how the environment (again, broader sense than just environment variables) must be set up; that's part of the problem. I know that at least the TEST_DIR and QEMU_DEFAULT_MACHINE environment variables must be set, but listing those in the error message gives an impression that it's all the user needs to do. Bad advice is worse than no advice. We could write something like "The TEST_DIR and QEMU_DEFAULT_MACHINE environment variables must be set and there may be other things that the tests may expect to have been set up. See what the 'check' script does if you want to invoke the tests some other way than running 'check'.", but I don't really see the additional value to the user. Sascha
Am 19.04.2016 um 18:49 hat Sascha Silbe geschrieben: > Dear Markus, > > Markus Armbruster <armbru@redhat.com> writes: > > > Say you had an accurate way to find out whether we're running under > > "check". You could then reject any attempt to run the test directly. > > I'd oppose that. > > > > It's okay to have test wrapper scripts to configure the tests just so. > > It's okay to tell people to use them. But "you can't do that, Dave" is > > not okay. [...] > > AFAICT the environment in which the individual test cases run isn't > well-defined. Currently it's indirectly defined by whatever "check" > does. > > The goal of the patch is to catch unwary developers invoking the tests > directly from the command line, providing them with useful advice. If > somebody wants to write another test runner (in place of "check"), it's > their responsibility to set up the environment appropriately. (They > could even set an environment variable "I_AM_CHECK=yes" if that's part > of the environment the tests expect). > > I'd be perfectly fine with defining the environment more clearly and > possibly extending the implementation to allow individual test cases to > be invoked directly (without a test runner like "check"). But that would > be 2.7 material. At this point in the 2.6 release cycle, this series is 2.7 material anyway. It's critical fixes only now. Kevin
Dear Kevin, Kevin Wolf <kwolf@redhat.com> writes: > At this point in the 2.6 release cycle, this series is 2.7 material > anyway. It's critical fixes only now. Fair enough. Sascha
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 0c0b533..8c7138f 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -46,7 +46,7 @@ if os.environ.get('QEMU_OPTIONS'): imgfmt = os.environ.get('IMGFMT', 'raw') imgproto = os.environ.get('IMGPROTO', 'file') -test_dir = os.environ.get('TEST_DIR', '/var/tmp') +test_dir = os.environ.get('TEST_DIR') output_dir = os.environ.get('OUTPUT_DIR', '.') cachemode = os.environ.get('CACHEMODE') qemu_default_machine = os.environ.get('QEMU_DEFAULT_MACHINE') @@ -441,6 +441,10 @@ def verify_quorum(): def main(supported_fmts=[], supported_oses=['linux']): '''Run tests''' + if test_dir is None or qemu_default_machine is None: + sys.stderr.write('Please run this test via ./check\n') + sys.exit(os.EX_USAGE) + debug = '-d' in sys.argv verbosity = 1 verify_image_format(supported_fmts)