diff --git a/test/jobenvs/job-exposed-port/Manifest.toml b/test/jobenvs/job-exposed-port/Manifest.toml new file mode 100644 index 000000000..13285dad4 --- /dev/null +++ b/test/jobenvs/job-exposed-port/Manifest.toml @@ -0,0 +1,287 @@ +# This file is machine-generated - editing it directly is not advised + +julia_version = "1.10.3" +manifest_format = "2.0" +project_hash = "a25eb6a8c2c61ed8d45ec4ff2a8af040379a123e" + +[[deps.Artifacts]] +uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" + +[[deps.Base64]] +uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" + +[[deps.BitFlags]] +git-tree-sha1 = "2dc09997850d68179b69dafb58ae806167a32b1b" +uuid = "d1d4a3ce-64b1-5f1a-9ba4-7e7e69966f35" +version = "0.1.8" + +[[deps.CodecZlib]] +deps = ["TranscodingStreams", "Zlib_jll"] +git-tree-sha1 = "59939d8a997469ee05c4b4944560a820f9ba0d73" +uuid = "944b1d66-785c-5afd-91f1-9de20f533193" +version = "0.7.4" + +[[deps.Compat]] +deps = ["TOML", "UUIDs"] +git-tree-sha1 = "b1c55339b7c6c350ee89f2c1604299660525b248" +uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" +version = "4.15.0" +weakdeps = ["Dates", "LinearAlgebra"] + + [deps.Compat.extensions] + CompatLinearAlgebraExt = "LinearAlgebra" + +[[deps.CompilerSupportLibraries_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" +version = "1.1.1+0" + +[[deps.ConcurrentUtilities]] +deps = ["Serialization", "Sockets"] +git-tree-sha1 = "6cbbd4d241d7e6579ab354737f4dd95ca43946e1" +uuid = "f0e56b4a-5159-44fe-b623-3e5288b988bb" +version = "2.4.1" + +[[deps.DataStructures]] +deps = ["Compat", "InteractiveUtils", "OrderedCollections"] +git-tree-sha1 = "1d0a14036acb104d9e89698bd408f63ab58cdc82" +uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" +version = "0.18.20" + +[[deps.Dates]] +deps = ["Printf"] +uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" + +[[deps.ExceptionUnwrapping]] +deps = ["Test"] +git-tree-sha1 = "dcb08a0d93ec0b1cdc4af184b26b591e9695423a" +uuid = "460bff9d-24e4-43bc-9d9f-a8973cb893f4" +version = "0.1.10" + +[[deps.HTTP]] +deps = ["Base64", "CodecZlib", "ConcurrentUtilities", "Dates", "ExceptionUnwrapping", "Logging", "LoggingExtras", "MbedTLS", "NetworkOptions", "OpenSSL", "Random", "SimpleBufferStream", "Sockets", "URIs", "UUIDs"] +git-tree-sha1 = "d1d712be3164d61d1fb98e7ce9bcbc6cc06b45ed" +uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3" +version = "1.10.8" + +[[deps.InteractiveUtils]] +deps = ["Markdown"] +uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" + +[[deps.JLLWrappers]] +deps = ["Artifacts", "Preferences"] +git-tree-sha1 = "7e5d6779a1e09a36db2a7b6cff50942a0a7d0fca" +uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" +version = "1.5.0" + +[[deps.JSON3]] +deps = ["Dates", "Mmap", "Parsers", "PrecompileTools", "StructTypes", "UUIDs"] +git-tree-sha1 = "eb3edce0ed4fa32f75a0a11217433c31d56bd48b" +uuid = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" +version = "1.14.0" + + [deps.JSON3.extensions] + JSON3ArrowExt = ["ArrowTypes"] + + [deps.JSON3.weakdeps] + ArrowTypes = "31f734f8-188a-4ce0-8406-c8a06bd891cd" + +[[deps.Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + +[[deps.LinearAlgebra]] +deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"] +uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" + +[[deps.Logging]] +uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" + +[[deps.LoggingExtras]] +deps = ["Dates", "Logging"] +git-tree-sha1 = "c1dd6d7978c12545b4179fb6153b9250c96b0075" +uuid = "e6f89c97-d47a-5376-807f-9c37f3926c36" +version = "1.0.3" + +[[deps.MIMEs]] +git-tree-sha1 = "65f28ad4b594aebe22157d6fac869786a255b7eb" +uuid = "6c6e2e6c-3030-632d-7369-2d6c69616d65" +version = "0.1.4" + +[[deps.Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" + +[[deps.MbedTLS]] +deps = ["Dates", "MbedTLS_jll", "MozillaCACerts_jll", "NetworkOptions", "Random", "Sockets"] +git-tree-sha1 = "c067a280ddc25f196b5e7df3877c6b226d390aaf" +uuid = "739be429-bea8-5141-9913-cc70e7f3736d" +version = "1.1.9" + +[[deps.MbedTLS_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" +version = "2.28.2+1" + +[[deps.Mmap]] +uuid = "a63ad114-7e13-5084-954f-fe012c677804" + +[[deps.MozillaCACerts_jll]] +uuid = "14a3606d-f60d-562e-9121-12d972cd8159" +version = "2023.1.10" + +[[deps.NetworkOptions]] +uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" +version = "1.2.0" + +[[deps.OpenBLAS_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] +uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" +version = "0.3.23+4" + +[[deps.OpenSSL]] +deps = ["BitFlags", "Dates", "MozillaCACerts_jll", "OpenSSL_jll", "Sockets"] +git-tree-sha1 = "38cb508d080d21dc1128f7fb04f20387ed4c0af4" +uuid = "4d8831e6-92b7-49fb-bdf8-b643e874388c" +version = "1.4.3" + +[[deps.OpenSSL_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "3da7367955dcc5c54c1ba4d402ccdc09a1a3e046" +uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" +version = "3.0.13+1" + +[[deps.OrderedCollections]] +git-tree-sha1 = "dfdf5519f235516220579f949664f1bf44e741c5" +uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" +version = "1.6.3" + +[[deps.Oxygen]] +deps = ["DataStructures", "Dates", "HTTP", "JSON3", "MIMEs", "Reexport", "RelocatableFolders", "Requires", "Sockets", "Statistics", "StructTypes"] +git-tree-sha1 = "edc978d60d435abfc674b3f9f31d74a7ec4740d8" +uuid = "df9a0d86-3283-4920-82dc-4555fc0d1d8b" +version = "1.5.8" + +[[deps.Parsers]] +deps = ["Dates", "PrecompileTools", "UUIDs"] +git-tree-sha1 = "8489905bcdbcfac64d1daa51ca07c0d8f0283821" +uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" +version = "2.8.1" + +[[deps.PrecompileTools]] +deps = ["Preferences"] +git-tree-sha1 = "5aa36f7049a63a1528fe8f7c3f2113413ffd4e1f" +uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a" +version = "1.2.1" + +[[deps.Preferences]] +deps = ["TOML"] +git-tree-sha1 = "9306f6085165d270f7e3db02af26a400d580f5c6" +uuid = "21216c6a-2e73-6563-6e65-726566657250" +version = "1.4.3" + +[[deps.Printf]] +deps = ["Unicode"] +uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" + +[[deps.Random]] +deps = ["SHA"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" + +[[deps.Reexport]] +git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" +uuid = "189a3867-3050-52da-a836-e630ba90ab69" +version = "1.2.2" + +[[deps.RelocatableFolders]] +deps = ["SHA", "Scratch"] +git-tree-sha1 = "ffdaf70d81cf6ff22c2b6e733c900c3321cab864" +uuid = "05181044-ff0b-4ac5-8273-598c1e38db00" +version = "1.0.1" + +[[deps.Requires]] +deps = ["UUIDs"] +git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7" +uuid = "ae029012-a4dd-5104-9daa-d747884805df" +version = "1.3.0" + +[[deps.SHA]] +uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" +version = "0.7.0" + +[[deps.Scratch]] +deps = ["Dates"] +git-tree-sha1 = "3bac05bc7e74a75fd9cba4295cde4045d9fe2386" +uuid = "6c6a2e73-6563-6170-7368-637461726353" +version = "1.2.1" + +[[deps.Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" + +[[deps.SimpleBufferStream]] +git-tree-sha1 = "874e8867b33a00e784c8a7e4b60afe9e037b74e1" +uuid = "777ac1f9-54b0-4bf8-805c-2214025038e7" +version = "1.1.0" + +[[deps.Sockets]] +uuid = "6462fe0b-24de-5631-8697-dd941f90decc" + +[[deps.SparseArrays]] +deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"] +uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" +version = "1.10.0" + +[[deps.Statistics]] +deps = ["LinearAlgebra", "SparseArrays"] +uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" +version = "1.10.0" + +[[deps.StructTypes]] +deps = ["Dates", "UUIDs"] +git-tree-sha1 = "ca4bccb03acf9faaf4137a9abc1881ed1841aa70" +uuid = "856f2bd8-1eba-4b0a-8007-ebc267875bd4" +version = "1.10.0" + +[[deps.SuiteSparse_jll]] +deps = ["Artifacts", "Libdl", "libblastrampoline_jll"] +uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" +version = "7.2.1+1" + +[[deps.TOML]] +deps = ["Dates"] +uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" +version = "1.0.3" + +[[deps.Test]] +deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] +uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[[deps.TranscodingStreams]] +git-tree-sha1 = "5d54d076465da49d6746c647022f3b3674e64156" +uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" +version = "0.10.8" +weakdeps = ["Random", "Test"] + + [deps.TranscodingStreams.extensions] + TestExt = ["Test", "Random"] + +[[deps.URIs]] +git-tree-sha1 = "67db6cc7b3821e19ebe75791a9dd19c9b1188f2b" +uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" +version = "1.5.1" + +[[deps.UUIDs]] +deps = ["Random", "SHA"] +uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" + +[[deps.Unicode]] +uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" + +[[deps.Zlib_jll]] +deps = ["Libdl"] +uuid = "83775a58-1f1d-513f-b197-d71354ab007a" +version = "1.2.13+1" + +[[deps.libblastrampoline_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" +version = "5.8.0+1" diff --git a/test/jobenvs/job-exposed-port/Project.toml b/test/jobenvs/job-exposed-port/Project.toml new file mode 100644 index 000000000..33d3cc733 --- /dev/null +++ b/test/jobenvs/job-exposed-port/Project.toml @@ -0,0 +1,3 @@ +[deps] +HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3" +Oxygen = "df9a0d86-3283-4920-82dc-4555fc0d1d8b" diff --git a/test/jobenvs/job-exposed-port/server.jl b/test/jobenvs/job-exposed-port/server.jl new file mode 100644 index 000000000..87e4c4733 --- /dev/null +++ b/test/jobenvs/job-exposed-port/server.jl @@ -0,0 +1,33 @@ +using Oxygen, HTTP + +const PORT = parse(Int, ENV["PORT"]) +const NREQUESTS = Ref{Int}(0) + +function results_json() + input = get(ENV, "TEST_INPUT", nothing) + input_escaped = if isnothing(input) + "null" + else + string('"', replace(input, '"' => "\\\""), '"') + end + return """ + { + "success": true, + "port": $(PORT), + "input": $(input_escaped), + "nrequests": $(NREQUESTS[]) + } + """ +end + +@get "/" function(req::HTTP.Request) + NREQUESTS[] += 1 + return results_json() +end + +@info "Starting server..." PORT +serve(; host="0.0.0.0", port = PORT) + +@info "Exiting the server" +ENV["RESULTS"] = results_json() +println(ENV["RESULTS"]) diff --git a/test/jobs-exposed-port-live.jl b/test/jobs-exposed-port-live.jl new file mode 100644 index 000000000..248931a83 --- /dev/null +++ b/test/jobs-exposed-port-live.jl @@ -0,0 +1,75 @@ +const JOBENV_EXPOSED_PORT = joinpath(@__DIR__, "jobenvs", "job-exposed-port") + +function wait_exposed_job_502(job::JuliaHub.Job; maxtime::Real=300) + # maxtime: it can definitely take at least 3 minutes for a job to start + start_time = time() + r = JuliaHub.request(job, "GET", "/"; auth, status_exception=false) + while r.status == 502 + @debug "Waiting for HTTP on job $(job.id) to start up (502-check)" time() - start_time maxtime + time() > start_time + maxtime && error("HTTP server on job $(job.id) didn't start in $(maxtime)s") + sleep(5) + r = JuliaHub.request(job, "GET", "/"; auth, status_exception=false) + end + return r +end + +function test_job_with_exposed_port(job::JuliaHub.Job; check_input::Bool=false, port::Integer) + job = wait_submission(job) + let r = wait_exposed_job_502(job) + @test r.status == 200 + json = JSON.parse(String(r.body)) + @test json isa AbstractDict + @test get(json, "success", nothing) === true + @test get(json, "port", nothing) == port + @test get(json, "nrequests", nothing) == 1 + if check_input + @test get(json, "input", nothing) == "foobar" + else + @test get(json, "input", nothing) === nothing + end + end + # For good measure, let's make another request, and make sure that NREQUESTS + # gets incremented correctly. + let r = JuliaHub.request(job, "GET", "/"; auth, status_exception=false) + @test r.status == 200 + json = JSON.parse(String(r.body)) + @test json isa AbstractDict + @test get(json, "success", nothing) === true + @test get(json, "nrequests", nothing) == 2 + end +end + +@testset "[LIVE] Test standard-batch image" begin + # We'll check that the 'standard-batch' image correctly matches + # up with the 'standard-interactive' image. + image = JuliaHub.batchimage("standard-batch"; auth) + @test image._interactive_product_name == "standard-interactive" + # Submit a job that will determine the correct product name from the batchimage. + job, _ = submit_test_job( + JuliaHub.appbundle(JOBENV_EXPOSED_PORT, "server.jl"; image); + expose = 8080, + alias = "exposed-port", auth, + ) + try + test_job_with_exposed_port(job; port=8080) + finally + # Kill the job, since we don't want the job to run unnecessarily long + JuliaHub.kill_job(job) + end +end + +@testset "[LIVE] Test standard-interactive (no image arg)" begin + # Submit a job, but don't specify the image explicitly. But instead we + # set env environment variable. + job, _ = submit_test_job( + JuliaHub.appbundle(JOBENV_EXPOSED_PORT, "server.jl"); + expose = 23456, env = Dict("TEST_INPUT" => "foobar"), + alias = "exposed-port-no-image", auth, + ) + try + test_job_with_exposed_port(job; port=23456, check_input=true) + finally + # Kill the job, since we don't want the job to run unnecessarily long + JuliaHub.kill_job(job) + end +end diff --git a/test/runtests-live.jl b/test/runtests-live.jl index d96ce420c..dde4f992c 100644 --- a/test/runtests-live.jl +++ b/test/runtests-live.jl @@ -56,6 +56,11 @@ JuliaHub.__AUTH__[] = auth include("jobs-live.jl") end + is_enabled("jobs-exposed-port") && + @testset "JuliaHub Jobs" begin + include("jobs-exposed-port-live.jl") + end + is_enabled("jobs-applications") && @testset "JuliaHub Apps" begin include("jobs-applications-live.jl") diff --git a/test/runtests.jl b/test/runtests.jl index 61a146496..67d97d868 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -52,6 +52,18 @@ function is_enabled(testname=nothing; args=ARGS) @warn "Skipping test set: $(testname) (windows tests disabled by default)" return false end + elseif isempty(enabled_tests) && run_live_tests && (testname == "jobs-exposed-port") + exposed_port_toggle_env = get(ENV, "JULIAHUBJL_LIVE_EXPOSED_PORT_TESTS", nothing) + if !(exposed_port_toggle_env in ("true", "false", nothing)) + error("Invalid value for JULIAHUBJL_LIVE_EXPOSED_PORT_TESTS: '$(exposed_port_toggle_env)'") + end + if exposed_port_toggle_env == "false" + @warn "Skipping test set: $(testname) (disabled via env variable)" + return false + else + @info "Running test set: $(testname)" + return true + end elseif (isempty(enabled_tests) && run_live_tests) || (testname in enabled_tests) @info "Running test set: $(testname)" return true