-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
Tests/bugfix: clean up build stage handling; no user config.yaml change (#12651, #12798, #13009) #12857
Tests/bugfix: clean up build stage handling; no user config.yaml change (#12651, #12798, #13009) #12857
Conversation
@tgamblin ping |
a337753
to
09d53a4
Compare
FYI. I just squashed the last 5 commits so this PR covers two commits:
|
@chissg Does this resolve your |
@tldahlgren Not sure I'd know until I interrupt a testing run in just the right (wrong) way and don't get the problem. I'll let you know if the dog doesn't bark! |
Np. |
FYI. The |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some questions, nothing that I'm confident needs to change but I wanted to ask a couple questions
I think some of these might be things that you've written exactly how they need to be written, and we'll just need to add comments for maintainability.
lib/spack/spack/test/stage.py
Outdated
spack.config.set('config', {'build_stage': [str(tmpdir)]}, scope='user') | ||
yield tmpdir | ||
spack.config.set('config', {'build_stage': current}, scope='user') | ||
shutil.rmtree(base) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if someone already happens to have a file in $spack
named test-stage
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough.
How about I make it a hidden file? Or I could sequence it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of the two options I mentioned, which would you prefer? Or do you have an alternate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI. Changed to hidden directory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That at least makes it more likely it's safe. We should probably put spack
in the name to be a little safer still
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a few preliminary questions/comments.
# Ensure the source directory exists | ||
source_path = new_stage.join(spack.stage._source_path_subdir) | ||
source_path.ensure(dir=True) | ||
monkeypatch.setattr(spack.stage, '_stage_root', new_stage_path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(question) Is the nomockstage
argument still required with this method of adjusting the stage path?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The mock_stage
fixture creates (during setup) and removes when present (during teardown) of the "well known" source path within the stage root.
Given mock_stage
is (now at) the function level and autouse
, this file system activity is performed whether the test case needs it or not. So I would think it would be better to either revisit having it autouse
(which should be mirrored in the use of the check_for_leftover_stage_files
fixture) OR make more use of the nomockstage
mark to avoid the unnecessary overhead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW I meant "revisit" in a separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I would think it would be better to either revisit having it autouse (which should be mirrored in the use of the check_for_leftover_stage_files fixture) OR make more use of the nomockstage mark to avoid the unnecessary overhead.
I prefer the former and agree that if it comes to this it ought to be dealt with in a later PR. However, I'm curious about:
Given mock_stage is (now at) the function level and autouse, this file system activity is performed whether the test case needs it or not.
I was wondering if there might be a way to make the tests work regardless of whether this runs. The goal of this is to ensure that for the purposes of testing that the stages are created in a test-managed directory. I'm wondering if introducing an additional root path component would reconcile the concerns of the tests: e.g. right now the stage path read from config.yaml
is relative to /
but we could add a module-level variable to Stage
that adjusts this root to be a temporary directory.
Does that seem reasonable? It could also be moved to another refactor PR but I prefer it to the approach of removing autouse
or using nomockstage
. I think it could be beneficial even in the case of removing the autouse
but IMO it would also make it so autouse
was only a performance problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't the one to add nomockstage
to address unit testing issues. (Not sure I can reproduce their problem.)
I'll have to give this more thought.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Created #13065
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK that makes sense for this one, I pulled the PR and for the other tests I tried with/without nomockstage
and it doesn't appear to be needed elsewhere.
8d29a2f
to
ef4b266
Compare
FYI. Once again narrowed this PR to two commits: one for nested overrides and the other for the tests. |
@becker33 @scheibelp ping |
cdd9023
to
67cf1ae
Compare
6d00f5e
to
12073ba
Compare
Can confirm that this fixes #13009 |
@becker33 @scheibelp ping Note there will likely be material conflicts requiring manual resolution between this and #12733 . |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think although there is at least one necessary use of nomockstage
, the other uses don't appear to be required. I pointed this out for most tests. Beyond that I have a couple other minor requests.
lib/spack/spack/test/stage.py
Outdated
"""Ensure an instance path stage root is a suitable path.""" | ||
assert spack.stage._stage_root is None | ||
# Make sure cached stage path value was changed appropriately | ||
assert spack.stage._stage_root == path |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think assert path == test_path
or assert spack.stage._stage_root == test_path
would be more-straightforward. As-is this is testing that spack.stage._stage_root == spack.stage.get_stage_root()
(which IMO is less important to test but if you disagree then I'd prefer assert spack.stage._stage_root == spack.stage.get_stage_root()
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. It looks like, from the diffs, this was an existing check that got "moved". I like the second option over the last one since path
is being used in another assertion at line 750.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed.
# Ensure the source directory exists | ||
source_path = new_stage.join(spack.stage._source_path_subdir) | ||
source_path.ensure(dir=True) | ||
monkeypatch.setattr(spack.stage, '_stage_root', new_stage_path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK that makes sense for this one, I pulled the PR and for the other tests I tried with/without nomockstage
and it doesn't appear to be needed elsewhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tmp_build_stage_dir
fixture does not appear to be required. I think it adds confusion since it modifies the config so I think it would be good to remove it here. I have added comments to the two tests that use it and how to remove it from them.
Note that it can be important for other tests that the previous settings be | ||
restored when the test case is over. | ||
""" | ||
def mock_stage_archive(tmp_build_stage_dir): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I set test_stage_path = spack.stage.get_stage_root()
then this doesn't seem to require the tmp_build_stage_dir
fixture (but it will in that case need the tmpdir
fixture for creating the archive later).
Since every test uses mock_stage
, this will be fine, and in fact this is kind of a strange piece of data to keep track of (although not from your work but rather a legacy behavior) since it's just used to verify that once the archive is staged, that the stage is created where you expect. Overall I figure this field ought to be removed from the Archive
object this creates but that doesn't need to happen here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW. This fixture is mock_stage_archive
, which is currently used by 14 stage tests, not mock_stage
. It is used to create an archive file for staging.
The mock_stage
fixture currently ensures the presence of the well-known source path for staging tests and removes the created path if it still exists.
As I revisit the two fixtures, I think I can see your concern but would still prefer to defer this matter to a separate PR due to other priorities.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added to #13065
|
||
spack.config.set('config', {'build_stage': current}, scope='user') | ||
|
||
|
||
def test_stage_create_replace_path(tmp_build_stage_dir): | ||
"""Ensure stage creation replaces a non-directory path.""" | ||
_, test_stage_path = tmp_build_stage_dir |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This instance of tmp_build_stage_dir
can also be removed and replaced with test_stage_path = spack.stage.get_stage_root()
, although you have to call stage.destroy
at the end of the test (and I recommend putting that in a try/finally
block to avoid impacts to other tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also relevant to addition of this issue in #13065
assert spack.stage._stage_root is None | ||
with spack.config.override('config:build_stage', stage_path): | ||
stage_root = spack.stage.get_stage_root() | ||
assert stage_path == stage_root |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think test_get_stage_root_in_spack
is already testing this (i.e. that the override is working properly) so I don't think that needs to be checked in this test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the harm in confirming it is as expected before performing purge
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Each test should focus on testing one thing (or as little as possible). Someone reading this test could get confused about how the assert confirms the behavior the test is focused on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have a reference for this statement?
Testing is very dependent on the structure/modularity of the code being tested.
Test checks depend on the nature (and granularity) of the test. For example, unit tests of functions/routines/methods should be limited to the associated side-effect(s), for example. (Ideally you'd have 'all' "happy path" and "unhappy" path tests for every function/routine/method covered.)
Tests that build up functionality may need more checks.
In this particular case, it combined get_stage_root
and the stage purge
functions. I am not comfortably with the idea of not ensuring that get_stage_root
is returning the expected path before calling purge
not because of the existing functionality but as "protection" against future changes.
Testing modification of the configuration is the point of the fixture, which also does cleanup. The fixture is used by Changing it as you suggest is not exactly trivial given the trade-offs. Can't this work be deferred to a separate issue? |
@becker33 @scheibelp ping Note that I question some of the changes wrt their inclusion in this PR and have not yet reduced this back down to the two main commits. |
656f538
to
9ab4b47
Compare
Fixes #12651
Fixes #12798
Fixes #13009
This PR restructures tests needing to temporarily change the
config:build_stage
path such that the tests no longer create or overwrite the setting in$HOME/.spack/config.yaml
. The change also appears to resolve stage path related issues when filtering tests on staging.This PR consists of two distinct commits. The first provides support for nested
overrides
scopes, which are created via thespack.config.override
context manager. The second commit changes how theautouse
'dmock_stage
and assorted test fixtures and tests establish their temporary stage directories.TODO :
stage._stage_root
instead of usingspack.config.override
)$spack/test-stage
(madetest-stage
hidden)test_get_stage_root_in_spack
(added directory presence check)overrides-
(internal overrides base name) aconfig.py
variablealways_access_path
name and fixturetest_stage_purge
docstringtest_stage
within a spack instance; ensure stage root is a directoryconfig.py
always_access_path
fixture to reflect it mockingcan_access
test_stage_purge
docstringspack
totest_stage
within a spack instance (to reduce odds of conflict)instance_path_for_stage
fixture code into the only test using itnomockstage
test_get_stage_root_in_spack
tmp_build_stage_dir
follow-on work