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

Tests/bugfix: clean up build stage handling; no user config.yaml change (#12651, #12798, #13009) #12857

Merged
merged 2 commits into from
Oct 10, 2019

Conversation

tldahlgren
Copy link
Contributor

@tldahlgren tldahlgren commented Sep 18, 2019

Fixes #12651
Fixes #12798
Fixes #13009

This PR restructures tests needing to temporarily change theconfig: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 the spack.config.override context manager. The second commit changes how the autouse'd mock_stage and assorted test fixtures and tests establish their temporary stage directories.

TODO :

  • Resolve test failures and errors (by setting stage._stage_root instead of using spack.config.override)
  • Address potential presence of $spack/test-stage (made test-stage hidden)
  • Address fixture vs test issue for test_get_stage_root_in_spack (added directory presence check)
  • Make overrides- (internal overrides base name) a config.py variable
  • Change always_access_path name and fixture
  • Update test_stage_purge docstring
  • Hide test_stage within a spack instance; ensure stage root is a directory
  • Move base name of config override scope to config.py
  • Change name and comment for always_access_path fixture to reflect it mocking can_access
  • Correct test_stage_purge docstring
  • Add spack to test_stage within a spack instance (to reduce odds of conflict)
  • Move instance_path_for_stage fixture code into the only test using it
  • Change a couple of stage test asserts
  • Remove stage-related use of nomockstage
  • Change docstring for test_get_stage_root_in_spack
  • Add TODO to address requested tmp_build_stage_dir follow-on work

@tldahlgren tldahlgren added WIP tests General test capability(ies) stage labels Sep 18, 2019
@tldahlgren tldahlgren self-assigned this Sep 18, 2019
@tldahlgren
Copy link
Contributor Author

@tgamblin ping

@tldahlgren tldahlgren changed the title [WIP] Tests/cleanup build stage [WIP] Tests: cleanup build stage handling Sep 19, 2019
@tldahlgren tldahlgren changed the title [WIP] Tests: cleanup build stage handling Tests: cleanup build stage handling Sep 19, 2019
@tldahlgren tldahlgren removed the WIP label Sep 19, 2019
@tldahlgren
Copy link
Contributor Author

FYI. I just squashed the last 5 commits so this PR covers two commits:

@tldahlgren
Copy link
Contributor Author

@chissg Does this resolve your $HOME/.spack/config.yaml issue?

@greenc-FNAL
Copy link
Member

@chissg Does this resolve your $HOME/.spack/config.yaml issue?

@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!

@tldahlgren
Copy link
Contributor Author

@chissg Does this resolve your $HOME/.spack/config.yaml issue?

@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.

@tldahlgren tldahlgren changed the title Tests: cleanup build stage handling Tests: clean up build stage handling Sep 19, 2019
@tldahlgren tldahlgren added the bugfix Something wasn't working, here's a fix label Sep 19, 2019
@tldahlgren
Copy link
Contributor Author

FYI. The $HOME/.spack/config.yaml file is only present for me when I run the tests. So it's absence after testing -- assuming I made sure to remove it before beginning the tests -- was how I confirmed this PR worked.

Copy link
Member

@becker33 becker33 left a 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/config.py Show resolved Hide resolved
lib/spack/spack/config.py Show resolved Hide resolved
lib/spack/spack/test/stage.py Outdated Show resolved Hide resolved
spack.config.set('config', {'build_stage': [str(tmpdir)]}, scope='user')
yield tmpdir
spack.config.set('config', {'build_stage': current}, scope='user')
shutil.rmtree(base)
Copy link
Member

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?

Copy link
Contributor Author

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.

Copy link
Contributor Author

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?

Copy link
Contributor Author

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.

Copy link
Member

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

lib/spack/spack/test/stage.py Show resolved Hide resolved
Copy link
Member

@scheibelp scheibelp left a 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.

lib/spack/spack/test/config.py Outdated Show resolved Hide resolved
lib/spack/spack/test/stage.py Outdated Show resolved Hide resolved
lib/spack/spack/test/stage.py Outdated Show resolved Hide resolved
lib/spack/spack/test/stage.py Outdated Show resolved Hide resolved
# 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)
Copy link
Member

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?

Copy link
Contributor Author

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.

Copy link
Contributor Author

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.

Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created #13065

Copy link
Member

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.

lib/spack/spack/test/stage.py Outdated Show resolved Hide resolved
@tldahlgren
Copy link
Contributor Author

FYI. Once again narrowed this PR to two commits: one for nested overrides and the other for the tests.

@tldahlgren
Copy link
Contributor Author

@becker33 @scheibelp ping

@tldahlgren tldahlgren force-pushed the tests/cleanup-build-stage branch 3 times, most recently from 6d00f5e to 12073ba Compare October 1, 2019 00:25
@adamjstewart
Copy link
Member

Can confirm that this fixes #13009

@tldahlgren
Copy link
Contributor Author

@becker33 @scheibelp ping

Note there will likely be material conflicts requiring manual resolution between this and #12733 .

@tldahlgren tldahlgren moved this from Todo to In Review in Spack v0.13.0 release Oct 8, 2019
Copy link
Member

@scheibelp scheibelp left a 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 Show resolved Hide resolved
lib/spack/spack/test/stage.py Outdated Show resolved Hide resolved
lib/spack/spack/test/stage.py Show resolved Hide resolved
lib/spack/spack/test/stage.py Outdated Show resolved Hide resolved
lib/spack/spack/test/config.py Outdated Show resolved Hide resolved
"""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
Copy link
Member

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()).

Copy link
Contributor Author

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.

Copy link
Contributor Author

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)
Copy link
Member

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.

@tldahlgren tldahlgren changed the title Tests: clean up build stage handling Tests/bugfix: clean up build stage handling Oct 9, 2019
Copy link
Member

@scheibelp scheibelp left a 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):
Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Contributor Author

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
Copy link
Member

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.

Copy link
Contributor Author

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

Spack v0.13.0 release automation moved this from In Review to In Progress Oct 9, 2019
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
Copy link
Member

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.

Copy link
Contributor Author

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?

Copy link
Member

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.

Copy link
Contributor Author

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.

@tldahlgren
Copy link
Contributor Author

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.

Testing modification of the configuration is the point of the fixture, which also does cleanup. The fixture is used by test_stage_create_replace_path and the mock_stage_archive fixture (the latter used for 14 tests).

Changing it as you suggest is not exactly trivial given the trade-offs.

Can't this work be deferred to a separate issue?

@tldahlgren
Copy link
Contributor Author

tldahlgren commented Oct 10, 2019

@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.

Spack v0.13.0 release automation moved this from In Progress to In Review Oct 10, 2019
@tldahlgren tldahlgren merged commit 93a44c8 into spack:develop Oct 10, 2019
Spack v0.13.0 release automation moved this from In Review to Done Oct 10, 2019
@tldahlgren tldahlgren deleted the tests/cleanup-build-stage branch October 15, 2019 20:55
@tldahlgren tldahlgren changed the title Tests/bugfix: clean up build stage handling Tests/bugfix: clean up build stage handling; no user config.yaml (#12651, #12798, #13009) Oct 16, 2019
@tldahlgren tldahlgren changed the title Tests/bugfix: clean up build stage handling; no user config.yaml (#12651, #12798, #13009) Tests/bugfix: clean up build stage handling; no user config.yaml change (#12651, #12798, #13009) Oct 16, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugfix Something wasn't working, here's a fix impact-medium refactoring stage tests General test capability(ies)
Projects
No open projects
5 participants