diff --git a/.github/workflows/FrontendTest.yml b/.github/workflows/FrontendTest.yml index a9b5d55961..07e6cf55da 100644 --- a/.github/workflows/FrontendTest.yml +++ b/.github/workflows/FrontendTest.yml @@ -63,17 +63,19 @@ jobs: - name: Run tests working-directory: ./test/frontend run: | - julia -e "import Pkg; Pkg.add(path=\"$GITHUB_WORKSPACE\"); Pkg.instantiate(); import Pluto; Pluto.run(port=$PLUTO_PORT, require_secret_for_access=false)" & # Run Pluto.jl server in the background + julia --project=$GITHUB_WORKSPACE -e 'import Pluto + # Run Pluto.jl server in the background + options = Pluto.Configuration.from_flat_kwargs(; + port=parse(Int, ENV["PLUTO_PORT"]), + require_secret_for_access=false, + ) + 🍭 = Pluto.ServerSession(; options) + server = Pluto.run!(🍭) - # Wait for Pluto to initialize - TIMES_TRIED=0 - until [ $TIMES_TRIED -eq 60 ] || $(curl --output /dev/null --silent --fail "http://localhost:$PLUTO_PORT/"); do - printf '.' - TIMES_TRIED=$((TIMES_TRIED+1)) - sleep 1 - done + run(`npm run test`) + + close(server)' - npm run test env: PLUTO_PORT: 1235 PLUTO_TEST_OFFLINE: ${{ github.ref_name == 'release' }} diff --git a/.github/workflows/Test.yml b/.github/workflows/Test.yml index 1e6d28c4f1..27443f0c5a 100644 --- a/.github/workflows/Test.yml +++ b/.github/workflows/Test.yml @@ -34,7 +34,7 @@ jobs: fail-fast: false matrix: # We test quite a lot of versions because we do some OS and version specific things unfortunately - julia-version: ["1.6", "1.7", "1.8", "1.9", "nightly"] + julia-version: ["1.6", "1.8", "1.9", "~1.10.0-0"] os: [ubuntu-latest, macOS-latest, windows-latest] steps: diff --git a/src/webserver/WebServer.jl b/src/webserver/WebServer.jl index a016fcadad..911a325704 100644 --- a/src/webserver/WebServer.jl +++ b/src/webserver/WebServer.jl @@ -103,12 +103,43 @@ function port_serversocket(hostIP::Sockets.IPAddr, favourite_port, port_hint) return port, serversocket end +struct RunningPlutoServer + http_server + initial_registry_update_task::Task +end + +function Base.close(ssc::RunningPlutoServer) + close(ssc.http_server) + wait(ssc.http_server) + wait(ssc.initial_registry_update_task) +end + +function Base.wait(ssc::RunningPlutoServer) + try + # create blocking call and switch the scheduler back to the server task, so that interrupts land there + while isopen(ssc.http_server) + sleep(.1) + end + catch e + println() + println() + Base.close(ssc) + (e isa InterruptException) || rethrow(e) + end + + nothing +end + """ run(session::ServerSession) Specifiy the [`Pluto.ServerSession`](@ref) to run the web server on, which includes the configuration. Passing a session as argument allows you to start the web server with some notebooks already running. See [`SessionActions`](@ref) to learn more about manipulating a `ServerSession`. """ function run(session::ServerSession) + Base.wait(run!(session)) +end + +function run!(session::ServerSession) if is_first_run[] is_first_run[] = false @info "Loading..." @@ -293,21 +324,7 @@ function run(session::ServerSession) will_update && println(" Updating registry done ✓") end - try - # create blocking call and switch the scheduler back to the server task, so that interrupts land there - while isopen(server) - sleep(.1) - end - catch e - println() - println() - close(server) - wait(server) - wait(initial_registry_update_task) - (e isa InterruptException) || rethrow(e) - end - - nothing + return RunningPlutoServer(server, initial_registry_update_task) end precompile(run, (ServerSession, HTTP.Handlers.Router{Symbol("##001")})) diff --git a/test/Configuration.jl b/test/Configuration.jl index 0507f688ea..4d2d6c2f54 100644 --- a/test/Configuration.jl +++ b/test/Configuration.jl @@ -64,8 +64,7 @@ end host = 🍭.options.server.host secret = 🍭.secret println("Launching test server...") - server_task = @async Pluto.run(🍭) - sleep(2) + server = Pluto.run!(🍭) local_url(suffix) = "http://$host:$port/$suffix" withsecret(url) = occursin('?', url) ? "$url&secret=$secret" : "$url?secret=$secret" @@ -123,7 +122,7 @@ end @test requeststatus(url, method) ∈ 200:399 # 3xx are redirects end - @async schedule(server_task, InterruptException(); error=true) + close(server) end @testset "disable mimetype via workspace_custom_startup_expr" begin diff --git a/test/webserver.jl b/test/webserver.jl index 0d94e1887c..009ff34631 100644 --- a/test/webserver.jl +++ b/test/webserver.jl @@ -32,25 +32,21 @@ using Pluto.WorkspaceManager: WorkspaceManager, poll base_url, ) 🍭 = Pluto.ServerSession(; options) - server_task = @async Pluto.run(🍭) + server = Pluto.run!(🍭) - # FYI, you should normally use a PlutoEvent for things we do in this test instead of polling! Don't use this as an example. - @test poll(10) do - server_running() - end + @test server_running() - sleep(20) - @test HTTP.get("http://$host:$port/edit"; status_exception=false).status == 404 + sleep(3) + @test poll(20) do + # should not exist because of the base url setting + HTTP.get("http://$host:$port/edit"; status_exception=false).status == 404 + end for notebook in values(🍭.notebooks) SessionActions.shutdown(🍭, notebook; keep_in_session=false) end - schedule(server_task, InterruptException(); error=true) - - # wait for the server task to finish - # normally this `wait` would rethrow the above InterruptException, but Pluto.run should catch for InterruptExceptions and not bubble them up. - wait(server_task) + close(server) end @testset "Exports" begin @@ -69,14 +65,16 @@ end # without notebook at startup - options = Pluto.Configuration.from_flat_kwargs(; port, launch_browser=false, workspace_use_distributed=true, require_secret_for_access=false, require_secret_for_open_links=false) + options = Pluto.Configuration.from_flat_kwargs(; + port, launch_browser=false, + workspace_use_distributed=true, + require_secret_for_access=false, + require_secret_for_open_links=false + ) 🍭 = Pluto.ServerSession(; options) - server_task = @async Pluto.run(🍭) + server = Pluto.run!(🍭) - # FYI, you should normally use a PlutoEvent for things we do in this test instead of polling! Don't use this as an example. - @test poll(10) do - server_running() - end + @test server_running() @test isempty(🍭.notebooks) @@ -112,10 +110,7 @@ end SessionActions.shutdown(🍭, notebook; keep_in_session=false) end - schedule(server_task, InterruptException(); error=true) - # wait for the server task to finish - # normally this `wait` would rethrow the above InterruptException, but Pluto.run should catch for InterruptExceptions and not bubble them up. - wait(server_task) + close(server) end end # testset