diff --git a/test/runtests.jl b/test/runtests.jl index b631e70f7..6c9c7291f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -72,6 +72,7 @@ include("helpers.jl") include("rounding.jl") include("parse.jl") include("plotting.jl") + include("thread-safety.jl") # Note: Run the build tests last to ensure that re-compiling the time zones files # doesn't interfere with other tests. diff --git a/test/thread-safety.jl b/test/thread-safety.jl new file mode 100644 index 000000000..16bd5ec93 --- /dev/null +++ b/test/thread-safety.jl @@ -0,0 +1,51 @@ +# Test that TimeZones.jl can be safely used in a multithreaded environment. +# Note that the number of threads being used cannot be changed dynamically, so +# this test file spawns a new julia process running with multiple threads. + +using Test + +const program = """ +using TimeZones +using Test + +@assert Threads.nthreads() > 1 "This system does not support multiple threads, so the thread-safety tests cannot be run." + +function create_zdt(year, month, day, tz_name) + ZonedDateTime(DateTime(year, month, day), TimeZone(tz_name)) +end +function cycle_zdts() + return [ + try + create_zdt(year, month, day, tz_name) + catch e + e isa Union{ArgumentError,NonExistentTimeError} || rethrow() + nothing + end + for year in 2000:2020 + for month in 1:5 + for day in 10:15 + for tz_name in timezone_names() + ] +end + +const outputs = Channel(Inf) +@sync begin + for _ in 1:15 + Threads.@spawn begin + put!(outputs, cycle_zdts()) + end + end +end +close(outputs) + +const tzs = collect(outputs) + +# Test that every Task produced the same result +allsame(x) = all(y -> y == first(x), x) +@test allsame(tzs) +""" + +@info "Running Thread Safety tests" +@testset "Multithreaded TimeZone construction" begin + run(`$(Base.julia_cmd()) -t8 --proj -E $(program)`) +end \ No newline at end of file