[Avocado-devel] Tests stable tmpdir
Lukáš Doktor
ldoktor at redhat.com
Mon Oct 31 11:31:42 UTC 2016
Dne 25.10.2016 v 17:15 Ademar Reis napsal(a):
> On Mon, Oct 24, 2016 at 06:14:14PM -0300, Cleber Rosa wrote:
>>
>> On 10/24/2016 10:27 AM, Amador Pahim wrote:
>>> Hello,
>>>
>>> I saw a number of requests about setUpClass/tearDownClass. We don't
>>> actually support them in Avocado, as already stated in our docs, but
>>> most of the requests are actually interested in have a temporary
>>> directory that can be the same throughout the job, so every test can
>>> use that directory to share information that is common to all the
>>> tests.
>>>
>>> One way to provide that would be exposing the Job temporary directory,
>>> but providing a supported API where a test can actually write to
>>> another test results can break our promise that tests are independent
>>> from each other.
>>>
>>
>> Yes, the initial goal of a job temporary directory is to prevent clashes
>> and allow proper cleanup when a job is finished. For those not familiar
>> with the current problems of (global) temporary directories:
>>
>> https://trello.com/c/qgSTIK0Y/859-single-data-dir-get-tmp-dir-per-interpreter-breaks-multiple-jobs
>
> Also, let's keep in mind that the architecture of Avocado is
> hierarchical and tests should not have access or knowledge about
> the job they're running on (I honestly don't know how much of
> this is true in practice today, but if it happens somewhere, it
> should be considered a problem).
>
> Anyway, what I want to say is that we should not expose a job
> directory to tests.
>
>>
>>
>>> Another way that comes to my mind is to use the pre/post plugin to
>>> handle that. On `pre`, we can create a temporary directory and set an
>>> environment variable with the path for it. On `post` we remove that
>>> directory. Something like:
>>>
>>> ```
>>> class TestsTmpdir(JobPre, JobPost):
>>> ...
>>>
>>> def pre(self, job):
>>> os.environ['AVOCADO_TESTS_TMPDIR'] = tempfile.mkdtemp(prefix='avocado_')
>>>
>>> def post(self, job):
>>> if os.environ.get('AVOCADO_TESTS_TMPDIR') is not None:
>>> shutil.rmtree(os.environ.get('AVOCADO_TESTS_TMPDIR'))
>>> ```
>>>
>>> Thoughts?
>>>
>>
Honestly I'd prefer this to be part of the API. Something like
`Test.shared_job_tmp` or so. But I know tests are not suppose to be
shared, it's not right, etc. but in reality they always are (unless we
create a new clean machine/container for each test).
Given that this solution is the closest to what I'd propose. I'd be
honest so I'd call it `SharedJobTmpdir` and `AVOCADO_SHARED_JOB_TMP`,
because that is what it is (no matter how we want to avoid the job, but
it creates the dir during pre-job and removes it during post-job).
Btw to give another alternative, one can always use `--mux-inject` or
env variables to add shared dir manually. But I consider this cumbersome.
>> I think this can be a valid solution, that promises very little to
>> tests. It doesn't break our assumption of how tests should not depend
>> on each other, and it reinforces that we aim at providing job level
>> orchestration.
>
> Thinking from the architecture perspective once again, this is a
> bit different from what you proposed before, but not that much
> (let's say it's a third-party "entity" called
> "AVOCADO_TESTS_TMPDIR" available to all processes in the job
> environment, unique per job).
>
> It's a bit better, but first of all, it should be named,
> implemented and even enabled in a more explicit way to prevent
> users from abusing it.
>
> But my real solution is below:
>
>>
>> Although, since we have discussed giving a job its own temporary dir,
>> and we already expose a lot via environment variables to tests:
>>
>> http://avocado-framework.readthedocs.io/en/latest/WritingTests.html#environment-variables-for-simple-tests
>>
>> And also to job pre/post script plugins:
>>
>> http://avocado-framework.readthedocs.io/en/latest/ReferenceGuide.html#script-execution-environment
>>
>> I'm afraid this could bring inconsistencies or clashes in the very near
>> future. What I propose for the immediate terms is to write a
>> contrib/example plugin, that we can either fold into the Job class
>> itself (giving it a real temporary dir, with variables exposed to test
>> processes) or make it a 1st class plugin.
>>
>> How does it sound?
>
> If we expose something like this as a supported API, we should
> make it as an "external resource available for tests" with proper
> access control (locking) mechanisms. In other words, this feature
> is a lot more about the locking API than about a global directory
> for tests.
>
> In summary, a "job/global directory available to all tests"
> should in fact be handled as "a global resource available to all
> tests". Notice it has no relationship to jobs whatsoever.
> Creating it per-job would be simply an implementation detail.
>
> Think of the hypothetical examples below and consider the
> architectural implication:
>
> (all tests in these examples are making use of the shared dir)
>
> $ export MY_DIR=~/tmp/foobar
> $ avocado run my-test.py
> $ avocado run my-test1.py my-test2.py
> $ avocado run my-test.py & avocado run my-test.py
> $ avocado run --enable-parallel-run my-test*.py
>
> Some of the above will break with today's Avocado. Now imagine we
> provide a locking API for shared resources. Tests could then do
> this:
>
> lock($MY_DIR)
> do_something...
> unlock($MY_DIR)
>
> Or maybe even better, simply declare they're using $MY_DIR during
> their entire execution via a decorator or some (future)
> dependency API:
>
> @using($MY_DIR)
> def ...
>
> With that in place, we could have a plugin, or even a first-class
> citizen API, to create and expose a unique directory per job.
>
> Thanks.
> - Ademar
>
There are several existing libraries to lock directories/files. I don't
think we need to implement them as one can download them from pip. The
only thing user require is the shared dir and than they can do:
```
from lockfile import LockFile
def setUp(self):
self.shared_dir = os.get("AVOCADO_SHARED_JOB_TMP")
assert self.shared_dir
with LockFile(self.shared_dir):
# do my stuff
with LockFile(os.path.join(self.shared_dir, "qemu")):
# do something inside qemu while allowing other tests
# to access shared_dir
```
Yes, we can eventually create our version and promote it in our
`avocado.utils` but even without it I see a big benefit in having share dir.
Lukáš
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 502 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/avocado-devel/attachments/20161031/b03a8e79/attachment.sig>
More information about the Avocado-devel
mailing list