Skip to content

Commit 11d491c

Browse files
authored
Test suite: Add coverage for some "unhappy" paths (error paths) (#46)
1 parent e49016d commit 11d491c

File tree

4 files changed

+131
-1
lines changed

4 files changed

+131
-1
lines changed

test/error_path_intentionally_fail.jl

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
mktempdir() do tmpdir
2+
fake_bindir = joinpath(tmpdir, "bin")
3+
fake_srun = joinpath(tmpdir, "bin", "srun")
4+
mkpath(fake_bindir)
5+
open(fake_srun, "w") do io
6+
println(io, "#!/usr/bin/env bash")
7+
println(io, "set -euf -o pipefail")
8+
# println(io, "set -x")
9+
println(io, "echo [stdout] fake-srun: INTENTIONALLY ERROR-ING")
10+
println(io, "echo [stderr] fake-srun: INTENTIONALLY ERROR-ING >&2")
11+
println(io, "exit 1")
12+
end
13+
chmod(fake_srun, 0o700) # chmod +x
14+
directory_separator = Sys.iswindows() ? ';' : ':'
15+
new_env = Dict{String, String}()
16+
new_env["SLURM_NTASKS"] = "8"
17+
new_env["SLURM_JOB_ID"] = "1234"
18+
if haskey(ENV, "PATH")
19+
old_path = ENV["PATH"]
20+
new_env["PATH"] = fake_bindir * directory_separator * old_path
21+
else
22+
new_env["PATH"] = fake_bindir
23+
end
24+
25+
@info "with old PATH" Sys.which("srun")
26+
withenv(new_env...) do
27+
@info "with new PATH" Sys.which("srun")
28+
29+
if Base.VERSION >= v"1.2-"
30+
T_expected = TaskFailedException
31+
else
32+
T_expected = Base.IOError
33+
end
34+
35+
mgr = SlurmClusterManager.SlurmManager()
36+
@test_throws T_expected Distributed.addprocs(mgr)
37+
end
38+
end

test/error_path_manager_timeout.jl

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
mktempdir() do tmpdir
2+
fake_bindir = joinpath(tmpdir, "bin")
3+
fake_srun = joinpath(tmpdir, "bin", "srun")
4+
mkpath(fake_bindir)
5+
open(fake_srun, "w") do io
6+
println(io, "#!/usr/bin/env bash")
7+
println(io, "set -euf -o pipefail")
8+
# println(io, "set -x")
9+
10+
# we only print this to stderr; don't print to stdout, or we won't hit the desired error path
11+
# (we'll hit a different error path instead, not the one we want to test)
12+
println(io, "echo [stderr] fake-srun: sleeping for 15 seconds... >&2")
13+
14+
# Bash sleep for 15-seconds:
15+
println(io, "sleep 15")
16+
17+
println(io, "echo [stdout] fake-srun: INTENTIONALLY ERROR-ING")
18+
println(io, "echo [stderr] fake-srun: INTENTIONALLY ERROR-ING >&2")
19+
println(io, "exit 1")
20+
end
21+
chmod(fake_srun, 0o700) # chmod +x
22+
directory_separator = Sys.iswindows() ? ';' : ':'
23+
new_env = Dict{String, String}()
24+
new_env["SLURM_NTASKS"] = "8"
25+
new_env["SLURM_JOB_ID"] = "1234"
26+
if haskey(ENV, "PATH")
27+
old_path = ENV["PATH"]
28+
new_env["PATH"] = fake_bindir * directory_separator * old_path
29+
else
30+
new_env["PATH"] = fake_bindir
31+
end
32+
33+
@info "with old PATH" Sys.which("srun")
34+
withenv(new_env...) do
35+
@info "with new PATH" Sys.which("srun")
36+
37+
if Base.VERSION >= v"1.2-"
38+
expected_outer_ex_T = TaskFailedException
39+
expected_inner_ex_INSTANCE = ErrorException("launch_timeout exceeded")
40+
else
41+
expected_outer_ex_T = ErrorException
42+
expected_inner_ex_INSTANCE = ErrorException("launch_timeout exceeded")
43+
end
44+
45+
mgr = SlurmClusterManager.SlurmManager(; launch_timeout = 2.0)
46+
test_result = @test_throws expected_outer_ex_T Distributed.addprocs(mgr)
47+
48+
cfg = ConfigForTestingTaskFailedException(;
49+
expected_outer_ex_T=expected_outer_ex_T,
50+
expected_inner_ex_INSTANCE=expected_inner_ex_INSTANCE,
51+
)
52+
test_task_failed_exception(test_result, cfg)
53+
end
54+
end

test/runtests.jl

+12-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import Distributed
66
import Test
77

88
# Bring some names into scope, just for convenience:
9-
using Test: @testset, @test, @test_logs
9+
using Test: @testset, @test, @test_throws, @test_logs, @test_skip, @test_broken
1010

1111
const original_JULIA_DEBUG = strip(get(ENV, "JULIA_DEBUG", ""))
1212
if isempty(original_JULIA_DEBUG)
@@ -73,3 +73,14 @@ end # testset "SlurmClusterManager.jl"
7373
)
7474
end
7575
end
76+
77+
include("util.jl")
78+
79+
@testset "Test some unhappy paths (error paths)" begin
80+
@testset "intentionally fail" begin
81+
include("error_path_intentionally_fail.jl")
82+
end
83+
@testset "manager's launch timeout" begin
84+
include("error_path_manager_timeout.jl")
85+
end
86+
end

test/util.jl

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
extract_test_result_value(test_result::Test.Pass) = test_result.value
2+
3+
recursively_unwrap_ex(ex::ErrorException) = ex
4+
recursively_unwrap_ex(ex::Base.IOError) = ex
5+
6+
@static if Base.VERSION >= v"1.2-"
7+
function recursively_unwrap_ex(outer_ex::TaskFailedException)
8+
new_thing = outer_ex.task.exception
9+
return recursively_unwrap_ex(new_thing)
10+
end
11+
end
12+
13+
Base.@kwdef struct ConfigForTestingTaskFailedException
14+
expected_outer_ex_T
15+
expected_inner_ex_INSTANCE
16+
end
17+
18+
function test_task_failed_exception(test_result::Test.Pass, cfg::ConfigForTestingTaskFailedException)
19+
observed_outer_ex = extract_test_result_value(test_result)
20+
@test observed_outer_ex isa cfg.expected_outer_ex_T
21+
22+
observed_inner_ex = recursively_unwrap_ex(observed_outer_ex)
23+
@test observed_inner_ex isa typeof(cfg.expected_inner_ex_INSTANCE)
24+
@test observed_inner_ex == cfg.expected_inner_ex_INSTANCE
25+
26+
return nothing
27+
end

0 commit comments

Comments
 (0)