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

Error out if the user explicitly tries to test a non-test tgt. #8402

Merged
merged 9 commits into from
Oct 9, 2019

Conversation

benjyw
Copy link
Contributor

@benjyw benjyw commented Oct 7, 2019

Previously we would apply the union filter to all targets.
So ./pants test path/to:non-test-target would noop.

Now we only apply the filter to targets that originated in a glob spec,
such as path/to/targets::. If the user tries to run tests on
a non-test target via a single address spec then we don't apply
the filter, and instead fail on attempting to cast the non-test
target to the TestTarget union (which yields a sensible error message).

This gives us the best of both worlds: We can give a sensible error,
instead of nooping, when the user specifies a single target, but
treat globs in the expected way.

This required introducing the concept of the "provenance" of a
BuildFileAddress. That is, the Spec it originated from. The term
"source" is overloaded in this context, so we use "provenance"
instead.

@Eric-Arellano
Copy link
Contributor

Awesome! I'll more closely review tomorrow.

Question in the meantime: do we care about parity with V1 behavior? V1 will still no-op, whereas V2 will have a nice error. I think this is fine—and I'm not sure where we'd even start to change this in V1—but worth discussing.

src/python/pants/build_graph/address.py Show resolved Hide resolved
src/python/pants/engine/build_files.py Outdated Show resolved Hide resolved
src/python/pants/engine/build_files.py Show resolved Hide resolved
# TODO(#6004): when streaming to live TTY, rely on V2 UI for this information. When not a
# live TTY, periodically dump heavy hitters to stderr. See
# https://github.com/pantsbuild/pants/issues/6004#issuecomment-492699898.
if union_membership.is_member(TestTarget, target.adaptor):
if (provenance_map.is_single_address(target.address) or
Copy link
Member

Choose a reason for hiding this comment

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

Neat!

I can't find the tickets that discuss this, but: one approach that would be parallel to how we implement "glob" validation would be to require that each Spec has at least one match. So even a glob like ./pants test ${dir}:: would fail if there were no tests in the directory.

Copy link
Member

Choose a reason for hiding this comment

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

...well, other than #221 and #3651, I suppose.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, I'm not convinced that specs should be required to match at least one "relevant" target. I'm not convinced of the converse either. :)

Copy link
Contributor

Choose a reason for hiding this comment

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

Cool!

@benjyw
Copy link
Contributor Author

benjyw commented Oct 7, 2019

Awesome! I'll more closely review tomorrow.

Question in the meantime: do we care about parity with V1 behavior? V1 will still no-op, whereas V2 will have a nice error. I think this is fine—and I'm not sure where we'd even start to change this in V1—but worth discussing.

Yeah, I don't think parity is expected or required...

Previously we would apply the union filter to all targets.
So `./pants test path/to:non-test-target` would noop.

Now we only apply the filter to targets that originated in a glob spec,
such as path/to/targets::. If the user tries to run tests on
a non-test target via a single address spec then we don't apply
the filter, and instead fail on attempting to cast the non-test
target to the TestTarget union (which yields a sensible error message).

This gives us the best of both worlds: We can give a sensible error,
instead of nooping, when the user specifies a single target, but
treat globs in the expected way.

This required introducing the concept of the "provenance" of a
BuildFileAddress. That is, the Spec it originated from. The term
"source" is overloaded in this context, so we use "provenance"
instead.
@benjyw
Copy link
Contributor Author

benjyw commented Oct 8, 2019

Ping, now that this is green :)

key, value = entry
return key
key, value = entry
return key


Copy link
Member

Choose a reason for hiding this comment

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

Unfortunately, this file seems to have been formatted with black =(

Copy link
Contributor

Choose a reason for hiding this comment

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

Skipping review of this because the diff is unclear to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm I'm not sure what happened here, I thought I'd reverted my attempts to apply black. Will fix it up.

_specificity = {
SingleAddress: 0,
SiblingAddresses: 1,
AscendantAddresses: 2,
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible for an end-user to type an ascendant address through the CLI, or is this only used in internal code? I'm wondering if this should even belong here.

Also, what is the reasoning for an ascendant address being more specific than a descendant address? I'm not able to give a good technical reason for this, but a descendant address "feels" more specific intuitively to me.

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 don't really know what ascendant addresses are for. I just know that they're there, so I had to do something with them. To me they are less specific because they span multiple levels, whereas siblings are all in the same dir.

Copy link
Contributor

Choose a reason for hiding this comment

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

Does it fail if we remove them from the dictionary? I suppose we should regardless have it as a matter of defensive programming.

Agreed that ascendant is less specific than sibling. I mean that ascendant also seems less specific than descendent. I would order it:

single > sibling > descendant > ascendant

}


def more_specific(spec1, spec2):
Copy link
Contributor

Choose a reason for hiding this comment

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

Type hints appreciated if you know them. I think this would be:

Suggested change
def more_specific(spec1, spec2):
def more_specific(spec1: Spec, spec2: Spec) -> bool:

)


def test_more_specific():
Copy link
Contributor

Choose a reason for hiding this comment

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

+1 for using the Pytest assert strategy rather than subclassing unittest

key, value = entry
return key
key, value = entry
return key


Copy link
Contributor

Choose a reason for hiding this comment

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

Skipping review of this because the diff is unclear to me.

# TODO(#6004): when streaming to live TTY, rely on V2 UI for this information. When not a
# live TTY, periodically dump heavy hitters to stderr. See
# https://github.com/pantsbuild/pants/issues/6004#issuecomment-492699898.
if union_membership.is_member(TestTarget, target.adaptor):
if (provenance_map.is_single_address(target.address) or
Copy link
Contributor

Choose a reason for hiding this comment

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

Cool!

src/python/pants/base/specs.py Outdated Show resolved Hide resolved
bfaddr = BuildFileAddress(None, 'bin', 'some/dir')
target_adaptor = PythonBinaryAdaptor(type_alias='python_binary')
with self.captured_logging(logging.INFO):
# Note that this is not the same error message the end user will see, as we're resolving
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd be interested in an integration test which actually shows that the error we should the user is a good one...

In general I worry that testing @console_rules as unit tests is kind of hard to reason about, and would maybe be interested in an integration test for the globbed case too, but in this one particularly I don't love that we're asserting that an unhelpful error is shown, and commenting to say that the user won't see such a bad error...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I don't love this either. But I'm pretty against integration tests for very specific bits of functionality. They have incredibly high overhead and we should be using them much more sparingly than we do. In so many cases they exist because some underlying functionality is too hard to test in isolation.

I'd prefer that we figure out a way to have run_rule apply the same union casting logic as in prod, and get the right error message that way.

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

Successfully merging this pull request may close these issues.

4 participants