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

[WIP/RFC] Rewrite testing infrastructure to live in Base #19567

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

kshyatt
Copy link
Contributor

@kshyatt kshyatt commented Dec 12, 2016

Move testdefs.jl to base. Modify runtests and write some
utility functions to let base Julia and packages use this function.

Now, a package can provide its own runtests.jl, or it can simply provide a choosetests.jl analogous to the one in Julia's test/. I wrote an example for Combinatorics.jl that looks like:

function choosetests(choices = [])
    testnames = ["numbers", "factorials", "combinations", "permutations", "partitions", "youngdiagrams"]
    tests = []
    skip_tests = []

    for (i, t) in enumerate(choices)
        if t == "--skip"
            skip_tests = choices[i + 1:end]
            break
        else
            push!(tests, t)
        end
    end

    if tests == ["all"] || isempty(tests)
        tests = testnames
    end

    node1_tests = []
    bigmemtests = []
    tests, node1_tests, bigmemtests, false
end

Just like the main Julia tests, this will allow package writers to specify if some tests use lots of memory or need to run on the first worker for other reasons. Otherwise, they can run tests in parallel using Julia's infrastructure rather than rolling their own. They'll also get to print the same statistics, for instance:
screen shot 2016-12-12 at 12 47 00

To do:

  • Document how to make this work for packages in the packages manual
  • Clean up testdefs (@yuyichao, your advice might be helpful?)
  • Fix Travis
  • Test against a variety of packages

Move `testdefs.jl` to base. Modify `runtests` and write some
utility functions to let base Julia *and* packages use this function.
@kshyatt kshyatt added needs docs Documentation for this change is required packages Package management and loading testsystem The unit testing framework and Test stdlib labels Dec 12, 2016
@kshyatt kshyatt requested a review from tkelman December 12, 2016 20:55
@@ -18,7 +18,7 @@ endif
$(TESTS):
@cd $(SRCDIR) && \
$(ULIMIT_TEST) \
$(call PRINT_JULIA, $(call spawn,$(JULIA_EXECUTABLE)) --check-bounds=yes --startup-file=no ./runtests.jl $@)
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we make sure we still have this file? It's very useful to run the tests without going through makefile in order to specify different options.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, I can put it back in.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That will also un-break Travis and AV, probably 😓

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! runtests.jl is back as a stub

if net_on
n = min(Sys.CPU_CORES, length(tests))
n > 1 && addprocs(n; exename=test_exename, exeflags=test_exeflags)
BLAS.set_num_threads(1)
Copy link
Member

Choose a reason for hiding this comment

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

Does this have to be set back to the default after performing the task that requires a single thread?

Run the Julia unit tests listed in `tests`, which can be either a string or an array of
strings, using `numcores` processors. (not exported)
"""
function runtests(tests = ["all"], numcores = ceil(Int, Sys.CPU_CORES / 2))
Copy link
Contributor

Choose a reason for hiding this comment

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

this should be deprecated

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 (hopefully!)

@@ -294,6 +294,7 @@ include("deepcopy.jl")
include("interactiveutil.jl")
include("replutil.jl")
include("test.jl")
include("testdefs.jl")
Copy link
Contributor

Choose a reason for hiding this comment

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

this should be in Base.Test, not Base

@kshyatt
Copy link
Contributor Author

kshyatt commented Dec 12, 2016

Should I add a kwarg to my base/test.jl runtests to specify the number of cores, like the function in interactiveutil.jl had?

@aviks
Copy link
Member

aviks commented Dec 13, 2016

Very cool. Will packages that support 0.5, or even 0.4, be able to use this at all. Even if not, maybe useful make the migration path clear in the documentation.

@kshyatt
Copy link
Contributor Author

kshyatt commented Dec 15, 2016

Any thoughts on why I'm hitting mem limit? Do I need to set the max rss in test/runtests as well?

end

if haskey(ENV, "JULIA_TEST_EXEFLAGS")
const test_exeflags = `$(Base.shell_split(ENV["JULIA_TEST_EXEFLAGS"]))`
Copy link
Contributor

Choose a reason for hiding this comment

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

No const

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sounds good

end

function runtests(names=["all"]; test_dir=joinpath(JULIA_HOME, Base.DATAROOTDIR, "julia/test/"), numcores::Int=ceil(Int, Sys.CPU_CORES / 2))
include(joinpath(test_dir, "choosetests.jl"))
Copy link
Contributor

Choose a reason for hiding this comment

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

I believe these includes should just move out of the function. This function shouldnt call include except on the test file

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 includes are in the function in case you want to pass the package's test dir in, and you can have your own choosetests.jl in Pkg.dir()/test

Copy link
Contributor

Choose a reason for hiding this comment

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

That doesn't sound like a good API. And it also doesn't apply to testdefs.jl, which should just be part of Base.

If a package needs to customize the tests it wants to run, it should just do that in runtests.jl and pass the test list to Base.runtests().

Copy link
Contributor

Choose a reason for hiding this comment

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

AFAICT doing this in choosetests.jl instead of runtests.jl doesn't really make it any easier for the packages. The most useful part of the base choosetests.jl is (IMHO) the --skip option and the all "meta"-test and this currently doesn't make it possible for the package to use it. It might be useful to provide a few helper functions for cmdline parsing but I honestly don't think the one we have in base is a particularly good one and packages are better off using sth like ArgParse.jl for that.

Even if a choosetests type of interface is wanted, it should be implemented as a callback rather than includeing a file.

@kshyatt
Copy link
Contributor Author

kshyatt commented Dec 15, 2016

Thanks for the detailed feedback, @yuyichao. The power of [RFC]! Do others (@tkelman, @StefanKarpinski) feel similarly? I'm happy to abandon this avenue if we think it won't be productive.

@tkelman
Copy link
Contributor

tkelman commented Dec 15, 2016

This'll take some design iteration I think. In #18740 I listed the following features as goals to make easy for packages to use the same functionality as base:

  1. parallel execution
  2. easily running subsets of tests (related: testsets argument to Pkg.test() #15404)
  3. pretty-printing

points 1 and 3 shouldn't be too complicated, it's point 2 that may need some feedback from package authors about how they'd like it to work. I'm also not sure if packages writing their own choosetests.jl is the best way to go about it, but I also haven't written packages with enough tests to make good use of this kind of thing. Maybe worth pinging for feedback on discourse with a cross-link here?

@KristofferC
Copy link
Member

I like this initiative. One of the thing that I don't like so much with package-testing (á la Pkg.test()) is that tests are just normal julia code that gets run from top to bottom with exceptions being thrown when an error is detected. In other words, there is no "Test Manager" that is one level above the tests being executed. I think this is needed for better pretty printing and error reporting.

So what I want is something along the lines where packages do not have a runtests.jl file that simply includes everything. Instead a bunch of independent test_x.jl exists in the test directory and it is the "Test Manager's" job to execute these, do pretty printing of passes and errors and exit the process with success or fail.

Am I correct that this PR would enable functionality for packages to do something like that.

@ed1d1a8d
Copy link

Any updates on these functionalities, particularly the ability to run tests parallel?

@StefanKarpinski
Copy link
Member

No, unfortunately this effort stalled out but it's still very much wanted.

@ed1d1a8d
Copy link

If I'm interested in taking up this effort, where would be the place to start?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs docs Documentation for this change is required packages Package management and loading testsystem The unit testing framework and Test stdlib
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants