This is an archive of the discontinued LLVM Phabricator instance.

[LIT] Add SuffixDispatchTest for use in libc++ and libc++abi tests.
AbandonedPublic

Authored by EricWF on Nov 10 2014, 4:33 PM.

Details

Summary

This is an attempt to lift common functionality needed by libc++ and libc++abi into LIT proper.

SuffixDispatchTest handles:

  • Reading XFAIL, REQUIRES, UNSUPPORTED, tags from the source file.
  • Calculating if a test is unsupported.
  • Invoking the test_runner based on the tests suffix.

The tags have the following semantics:

  • XFAIL: Tests that are known failures and should be fixed.
  • UNSUPPORTED: Tests that are not relevant given a set of features.
  • REQUIRES: Mirrors UNSUPPORTED

SuffixDispatchTest allows tests with different suffixes to be handled in different ways. In libc++ .pass.cpp tests must compile and execute successfully and .fail.cpp tests must fail to compile. We can provide two different handlers to SuffixDispatchTest as follows:

test_format = SuffixDispatchTest()
test_format.add_suffix_test('.pass.cpp', PassTestHandler(...))
test_format.add_suffix_test('.fail.cpp', FailTestHandler(...))

Test handlers are expected to provide the following signature:

result,report = handler(test, lit_config)

Where:

  • result is a instance of ResultCode
  • report is a string representing the test that was run and the output.
  • test is an instance of lit.Test
  • lit_config is the global lit configuration object.

CompileAndExecuteTestRunner is a test runner for use with SuffixDispatchTest. It attempts to compile and run an executable.

I have patches to move libc++ and libc++abi over to the new format once this is accepted.

Diff Detail

Event Timeline

EricWF updated this revision to Diff 16020.Nov 10 2014, 4:33 PM
EricWF retitled this revision from to [LIT] Add SuffixDispatchTest for use in libc++ and libc++abi tests..
EricWF updated this object.
EricWF edited the test plan for this revision. (Show Details)
EricWF added reviewers: ddunbar, jroelofs, danalbert.
EricWF set the repository for this revision to rL LLVM.
EricWF added a subscriber: Unknown Object (MLST).
jroelofs edited edge metadata.Nov 11 2014, 6:59 AM

Excellent, I like it!

You've got a "thumbs up" from me, but I'd like to hear @ddunbar and @danalbert's opinions on it too.

Also, can you post the corresponding libcxxabi and libcxx parts of this in another review?

Cheers,

Jon

utils/lit/lit/formats/suffixdispatchtest.py
39

_parse_metadata_line or _metadata_line_matches perhaps? 'handle' is a bit hand-wavey.

91

Trailing comma.

107

I think you can do this in python....

for (suffix, test) in self.suffix_tests:
  if name.endswith(suffix):
    test_runner = test
    break
112

When does this happen? Should it be an 'assert False'?

utils/lit/lit/util.py
149

Some comments on these two functions would be nice here to explain the "why" behind them. At the moment I don't understand why these are needed.

EricWF updated this object.Nov 11 2014, 10:36 PM
EricWF edited edge metadata.

@jroelofs Thanks for the review.
I'm going to remove the handling of UNSUPPORTED-XFAIL and REQUIRES-XFAIL tomorrow. They make things needlessly complex and provide little value. Please don't take a look at it until then.

utils/lit/lit/formats/base.py
25–28

This allows suffixes to have multiple extensions ex: .pass.cpp

utils/lit/lit/formats/suffixdispatchtest.py
39

Sounds good thanks.

107

Cool! That's so much cleaner. Thanks.

112

lit_config.fatal will kill the process. This will happen when a test is matched to a suffix in config.suffixes but no test handler has been registered for that suffix.

jroelofs added inline comments.Nov 12 2014, 8:16 AM
utils/lit/lit/formats/suffixdispatchtest.py
112

Ah. A comment here explaining that might save someone a bit of head-scratching later.

danalbert requested changes to this revision.Nov 12 2014, 9:25 PM
danalbert edited edge metadata.

A bunch of nits, a few design improvements, and a couple questions, but I think this is definitely something that will save us time in the long run. Thanks!

utils/lit/lit/formats/__init__.py
3

I much prefer

from foo import (bar,
                 baz)

Trailing backslashes are gross.

utils/lit/lit/formats/base.py
25

This looks odd to me, but phab isn't giving me any context...

There's an outer loop here somewhere (judging by the yield below). I assume it's looping over each test?

You then have if filepath.endswith(ext) within the for loop, making all but one iteration a no-op. Am I missing something here?

utils/lit/lit/formats/suffixdispatchtest.py
2

I've always loved that Python has an import for a time machine.

5

Sort these.

16

't'.upper()

20

The single worst thing about Python is its syntax for super.

23

Is there ever a case where these aren't known at initialization time of the object? I'd vote for just removing these two methods (especially delete).

85

Alignment.

96

Alignment.

99

Alignment.

107

You wanted a dict.

test_runners = {
    ".pass": PassRunner(),
    ".fail": FailRunner()
}

This block would become test_runner = test_runners[suffix].

114

Spaces after commas

130

Space after comma

148

Why do we have to pass -o for this? Isn't it pretty obvious we want the link command to generate an output?

150

Spaces after commas

exit_code to fit with the rest of the file

152

sac

160

This looks like an implementation detail that leaked (though I appreciate the irony).

I'd like to see if we can factor this out some how... but I'm not coming up with anything right now.

164

Why a docstring?

167

sac

173

sac

utils/lit/lit/util.py
9

sort these

149

Yeah, I find it really difficult to believe that a python library needs its own to_string.

159

Oh, I see it wasn't you that added it. Still confused that we needed it...

189

Why do we need this? What's wrong with subprocess.Popen(..., stdout=subprocess.PIPE, stderr=subprocess.PIPE)?

194

sac (and not before)

206

exit_code

234

Docstrings?

First line added is unconditional, no sense in report = '' before

240

sac

247

sac

276

lit.util doesn't seem like the right place for this (but I haven't had a look around to know what the right place would be).

279

The copy probably isn't necessary.

282

Isn't this implicit?

285

For the way this is used, I think def compilerCmd(self, in, out) would make more sense.

Same goes for the rest of these.

This revision now requires changes to proceed.Nov 12 2014, 9:25 PM
EricWF updated this revision to Diff 16132.Nov 12 2014, 10:04 PM
EricWF edited edge metadata.

Remove UNSUPPORTED-XFAIL and REQUIRES-XFAIL tags. I haven't addressed @danalbert's comments yet.

EricWF updated this object.Nov 12 2014, 10:04 PM
EricWF edited edge metadata.

I've addressed most of @danalbert's comments. Patch to follow.

utils/lit/lit/formats/__init__.py
3

Sounds good. I'll make the change.

utils/lit/lit/formats/base.py
25

Nope, I think you've found a bug. I'll make a change.

utils/lit/lit/formats/suffixdispatchtest.py
16

Nice way to put that :)

23

Perhaps. I need to look into this more but the use case I envisioned was that sub directories may want to add/remove test suffixes.

107

I disagree. The problem is that I don't know how to split the filename into name + suffix. For example a test.fail.cpp. How do you know where to split the test name?

148

To make the interface simple. Then you have to worry about what parameter you pass to compileLinkCmd is the output file and which one is a set of extra arguments.

After playing around with it I decided the simplest interface is to just take an extra list of options.

160

I'm more alright having this here as opposed to in libc++ and libc++abi's lit.cfg. The valgrind stuff is all defined by lit (and is not local to libc++).

164

No idea. Removed.

utils/lit/lit/util.py
149

Not sure. These already existed in the utility library. I'm just trying not to break them :S. I'll inquire as to why they are needed.

189

Color output! By tricking the sub process into thinking it's running in a TTY it will produce color output. I HATE that we currently lose clang pretty formatting when it gets passed through LIT.

206

exitCode is the current naming in the rest of this file.

276

Your probably right but IDK where to put it either. It's a surprising useful abstraction.

279

I disagree. I already have a use-case for it in the patch that makes libc++ use this.

compile_flags = [...]
cxx = Compiler(compile_flags)
compile_flags.extend(sanitizer_args)
sanitized_cxx = Compiler(compile_flags)
282

Don't think so. Python has shallow copy semantics on classes right?

285

I still want to provide extra compile and link flags. meaning that the interface would look like:

def compileCmd(self, in, out=None, compile_flags=[])

Now you have to name the extra flags if you want to pass them. Instead I really thinks it's cleaner to let the user just pass arbitrary flags.
If you feel strongly I'll make the change, but I had originally implemented it as you suggested and I really didn't like it.

EricWF updated this revision to Diff 16133.Nov 12 2014, 10:46 PM

Revision that addresses @danalbert's comments.

EricWF updated this revision to Diff 16134.Nov 12 2014, 10:47 PM

Remove more usage of docstrings.

danalbert added inline comments.Nov 13 2014, 11:13 AM
utils/lit/lit/formats/suffixdispatchtest.py
23

Hmm. I'm guessing YAGNI. Even if some subdirectory has different needs (sounds unlikely), they can just add it at the top level.

107

What's wrong with testname.split('.')[-2]?

160

Ah, didn't realize it was a common LIT thing. Works for me.

utils/lit/lit/util.py
149

Well, looking at it, it's for handling transformation of a unicode byte-string into a text string... but what I don't understand is why we'd ever have to deal with that input...

189

Oh, yeah, that's rather nice. The implementation is rather disgusting though :) (I blame subprocess.Popen, not you).

What's wrong with -fcolorize=always?

If -fcolorize=always won't work, I think it would be better to make a PtyPipe class and pass that to executeCommand (with the default arugments being subprocess.PIPE).

206

out_pty and err_pty are the other style though. Let's be consistent throughout the file, whatever that may be.

276

We can keep it here for now if no one has a better home for it,

279

This might be the functional programmer in me showing, but I would write that as

compile_flags = [...]
cxx = Compiler(compile_flags)
sanitized_cxx = Compiler(compile_flags + sanitizer_args)
282

I suppose this depends on the resolution of the comments on 279. I think a shallow copy should be sufficient.

285

The above interface looks right to me.

Keep in mind that hard coding the -o at the call site means that we'll have implementation details of the compiler leaking out of the abstraction and each call site will be

if compiler_under_test_is_msvc:
    compiler.compileCmd(whatever_msvc_needs)
else:
    compiler.compileCmd(['-o', out_file, in_file])

The Compiler should be an abstraction. How the compiler (the actual compiler, not Compiler) works should be irrelevant from the outside.

danalbert added inline comments.Nov 13 2014, 11:21 AM
utils/lit/lit/formats/suffixdispatchtest.py
71

I don't think this TODO should be removed. I read this to mean that REQUIRES and UNSUPPORTED should be moved into lit.test (so they work for any test runner).

125

Alignment.

utils/lit/lit/util.py
95

This docstring format will mess with tools.

"""Short, single sentence (usually), description.

Longer description in
paragraph format.
"""

Copy in jroelofs' comments from email.

utils/lit/lit/formats/suffixdispatchtest.py
23

jroelofs: What benefit do we get from shoving everything into the constructors?

I'm just not convinced we'll ever have that many of these. All we really get with my approach is not having these two methods, but I'm not convinced that the current approach gives us anything useful.

107

jroelofs: That assumes test suffixes have at most two '.'s in them...

No, it assumes it has at _least_ that many. Given 'foo.bar.baz.buzz.qux.cpp', this will still choose qux, which aiui is the desired behavior (and lets us move to a data structure that actually cleanly represents this data).

utils/lit/lit/util.py
149

jroelofs: C can have unicode in it, no?

I think what I'm actually misunderstanding here is how that then gets handled by python. I'm assuming that python is smart enough to have already done this for anything returned from subprocess.Popen.communicate.

279

jroelofs: Me too.

jroelofs added inline comments.Nov 13 2014, 12:15 PM
utils/lit/lit/formats/suffixdispatchtest.py
107

What I really meant is that this limits us to test suffixes with at most two '.'s in them. I.e. given foo.bar.baz.buzz.qux.cpp, then this wouldn't work:

test_format.add_suffix_test('.buzz.qux.cpp', FailTestHandler(...))
utils/lit/lit/util.py
159

Uhgreed.

EricWF updated this revision to Diff 16172.Nov 13 2014, 12:23 PM

Addresses most of @danalbert's comments.

EricWF added inline comments.Nov 13 2014, 12:24 PM
utils/lit/lit/formats/suffixdispatchtest.py
107

Because I wasn't committing to the suffix being the second part of the extension. I much prefer it matching suffixes is the simplest form.

utils/lit/lit/util.py
189

What's wrong with -fcolorize=always?

This solution can be used with any program that by default will output color on a TTY. There was support for this change because FileCheck apparently outputs in color on TTY's as well.

Also GCC doesn't support it, so we would have to detect if the flag is supported.

If -fcolorize=always won't work, I think it would be better to make a PtyPipe class and pass that to executeCommand (with the default >arugments being subprocess.PIPE).

I'll try that out, but I think the semantics are just different enough that it's not likely to work.

206

Ok.

279

This might be the functional programmer in me showing, but I would write that as

compile_flags = [...]
cxx = Compiler(compile_flags)
sanitized_cxx = Compiler(compile_flags + sanitizer_args)

I'll concede that my example is bad style, but copying lists into objects is the existing style in LIT.
Also I don't see how copying it would cause a problem but I do see how not copying it is a problem.

Is there a reason you want the compile_flags in the Compiler object to refer to the same list it was passed?
I don't see the use case for this.

How strongly do you feel about this change?

282

I'll make the change but I suspect this might be needed since you'll likely pass the same Compiler object to multiple test runners. Each of these test runners may want to modify it.

285

Alright, I'll make the change.

EricWF added inline comments.Nov 13 2014, 12:27 PM
utils/lit/lit/formats/suffixdispatchtest.py
107

It limits us to exactly two. libcxxabi test suit simply uses '.cpp' as the suffix.

@ddunbar ping. Do you have any thoughts?

ddunbar edited edge metadata.Dec 3 2014, 1:13 PM

For my own context, is part of the motivation here that you want to share
this test format between multiple repositories?

  • Daniel

Ping.

@ddunbar, Do you want me to remove the executeCommandPTY stuff since that is unrelated to the rest of this?

In D6206#29, @ddunbar wrote:

For my own context, is part of the motivation here that you want to share
this test format between multiple repositories?

  • Daniel

Gaa Sorry @ddunbar, I entirely missed this.

Yes. both libc++ and libc++abi will use SuffixDispatchTest. They both currently have different versions of basically the same code.

I see.

Generally speaking, I think it is great to improve the implementation of
this test format, but I don't think that it meets the bar to be included in
lit proper. I want to keep lit pretty general purpose, and this test format
is just so specific to the libc.* use case that its hard to imagine many
other clients.

Part of my hesitation comes from feeling that this isn't such a great test
format to start with. As a format, it isn't all that flexible (mangling
part of the metadata into the filename really doesn't leave much room for
extension, and then if we start putting metadata in the file too we have it
in two places).

Is there another way you can manage sharing the test format implementation
with those repositories?

Alternately, it seems like the main thing going for this test format is it
makes sense when you have a large number of tests which all run the same
action. We actually end up having that problem in other places too (there
are subsets of clang tests which all follow the same pattern), so I wonder
if there might some value in exploring an extension of the ShTest format
that solved this problem explicitly, and then migrating the libc.* tests to
that.

For example, just to brainstorm, if the ShTest format had a way to use a
"prelude" script for all files in a directory, could that be the basis for
using the ShTest format for libc++?

  • Daniel
EricWF abandoned this revision.Dec 9 2014, 7:13 PM
In D6206#32, @ddunbar wrote:

I see.

Generally speaking, I think it is great to improve the implementation of
this test format, but I don't think that it meets the bar to be included in
lit proper. I want to keep lit pretty general purpose, and this test format
is just so specific to the libc.* use case that its hard to imagine many
other clients.

Part of my hesitation comes from feeling that this isn't such a great test
format to start with. As a format, it isn't all that flexible (mangling
part of the metadata into the filename really doesn't leave much room for
extension, and then if we start putting metadata in the file too we have it
in two places).

Is there another way you can manage sharing the test format implementation
with those repositories?

Alternately, it seems like the main thing going for this test format is it
makes sense when you have a large number of tests which all run the same
action. We actually end up having that problem in other places too (there
are subsets of clang tests which all follow the same pattern), so I wonder
if there might some value in exploring an extension of the ShTest format
that solved this problem explicitly, and then migrating the libc.* tests to
that.

For example, just to brainstorm, if the ShTest format had a way to use a
"prelude" script for all files in a directory, could that be the basis for
using the ShTest format for libc++?

  • Daniel

After seeing more of LIT, I agree this is not a good test format. Most of the handling of internal metadata already exists within TestRunner.parseIntegratedTestScript. I'll lift that to where it belongs. I'll also remove Compiler and CompileAndExecuteTestRunner. Those probably shouldn't live inside lit.

After removing all of that there is no more code that really needs to be shared between libc++ and libc++abi. I'll put the executeCommandPty changes in a different patch and submit them separately.

Thanks for the input.

Sounds good!

  • Daniel