mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-10-12 06:25:56 +08:00
Improve tests (#1627)
This commit is contained in:
parent
35b8bb73df
commit
b60428c94d
11 changed files with 65 additions and 31 deletions
|
@ -188,6 +188,7 @@ defmodule Livebook.Runtime.ErlDist.NodeManager do
|
||||||
opts
|
opts
|
||||||
|> Keyword.put_new(:ebin_path, ebin_path(state.tmp_dir))
|
|> Keyword.put_new(:ebin_path, ebin_path(state.tmp_dir))
|
||||||
|> Keyword.put_new(:tmp_dir, child_tmp_dir(state.tmp_dir))
|
|> Keyword.put_new(:tmp_dir, child_tmp_dir(state.tmp_dir))
|
||||||
|
|> Keyword.put_new(:base_path_env, System.get_env("PATH", ""))
|
||||||
|
|
||||||
{:ok, server_pid} =
|
{:ok, server_pid} =
|
||||||
DynamicSupervisor.start_child(state.server_supervisor, {ErlDist.RuntimeServer, opts})
|
DynamicSupervisor.start_child(state.server_supervisor, {ErlDist.RuntimeServer, opts})
|
||||||
|
|
|
@ -47,6 +47,10 @@ defmodule Livebook.Runtime.ErlDist.RuntimeServer do
|
||||||
those from file inputs. When not specified, operations relying
|
those from file inputs. When not specified, operations relying
|
||||||
on the directory are not possible
|
on the directory are not possible
|
||||||
|
|
||||||
|
* `:base_path_env` - the value of `PATH` environment variable
|
||||||
|
to merge new values into when setting environment variables.
|
||||||
|
Defaults to `System.get_env("PATH", "")`
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def start_link(opts \\ []) do
|
def start_link(opts \\ []) do
|
||||||
GenServer.start_link(__MODULE__, opts)
|
GenServer.start_link(__MODULE__, opts)
|
||||||
|
@ -300,7 +304,8 @@ defmodule Livebook.Runtime.ErlDist.RuntimeServer do
|
||||||
extra_smart_cell_definitions: Keyword.get(opts, :extra_smart_cell_definitions, []),
|
extra_smart_cell_definitions: Keyword.get(opts, :extra_smart_cell_definitions, []),
|
||||||
memory_timer_ref: nil,
|
memory_timer_ref: nil,
|
||||||
last_evaluator: nil,
|
last_evaluator: nil,
|
||||||
initial_path: System.get_env("PATH", ""),
|
base_env_path:
|
||||||
|
Keyword.get_lazy(opts, :base_env_path, fn -> System.get_env("PATH", "") end),
|
||||||
ebin_path: Keyword.get(opts, :ebin_path),
|
ebin_path: Keyword.get(opts, :ebin_path),
|
||||||
tmp_dir: Keyword.get(opts, :tmp_dir)
|
tmp_dir: Keyword.get(opts, :tmp_dir)
|
||||||
}}
|
}}
|
||||||
|
@ -574,7 +579,7 @@ defmodule Livebook.Runtime.ErlDist.RuntimeServer do
|
||||||
def handle_cast({:put_system_envs, envs}, state) do
|
def handle_cast({:put_system_envs, envs}, state) do
|
||||||
envs
|
envs
|
||||||
|> Enum.map(fn
|
|> Enum.map(fn
|
||||||
{"PATH", path} -> {"PATH", state.initial_path <> os_path_separator() <> path}
|
{"PATH", path} -> {"PATH", state.base_env_path <> os_path_separator() <> path}
|
||||||
other -> other
|
other -> other
|
||||||
end)
|
end)
|
||||||
|> System.put_env()
|
|> System.put_env()
|
||||||
|
@ -585,7 +590,7 @@ defmodule Livebook.Runtime.ErlDist.RuntimeServer do
|
||||||
def handle_cast({:delete_system_envs, names}, state) do
|
def handle_cast({:delete_system_envs, names}, state) do
|
||||||
names
|
names
|
||||||
|> Enum.map(fn
|
|> Enum.map(fn
|
||||||
"PATH" -> {"PATH", state.initial_path}
|
"PATH" -> {"PATH", state.base_env_path}
|
||||||
name -> {name, nil}
|
name -> {name, nil}
|
||||||
end)
|
end)
|
||||||
|> System.put_env()
|
|> System.put_env()
|
||||||
|
|
|
@ -124,7 +124,13 @@ defmodule Livebook.Runtime.Evaluator.IOProxy do
|
||||||
|
|
||||||
def handle_cast({:tracer_updates, updates}, state) do
|
def handle_cast({:tracer_updates, updates}, state) do
|
||||||
state = update_in(state.tracer_info, &Evaluator.Tracer.apply_updates(&1, updates))
|
state = update_in(state.tracer_info, &Evaluator.Tracer.apply_updates(&1, updates))
|
||||||
{:noreply, state}
|
|
||||||
|
modules_defined =
|
||||||
|
for {:module_defined, module, _vars} <- updates,
|
||||||
|
into: state.modules_defined,
|
||||||
|
do: module
|
||||||
|
|
||||||
|
{:noreply, %{state | modules_defined: modules_defined}}
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
|
@ -133,12 +139,7 @@ defmodule Livebook.Runtime.Evaluator.IOProxy do
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_call(:get_tracer_info, _from, state) do
|
def handle_call(:get_tracer_info, _from, state) do
|
||||||
modules_defined =
|
{:reply, state.tracer_info, state}
|
||||||
state.tracer_info.modules_defined
|
|
||||||
|> Map.keys()
|
|
||||||
|> Enum.into(state.modules_defined)
|
|
||||||
|
|
||||||
{:reply, state.tracer_info, %{state | modules_defined: modules_defined}}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
|
|
|
@ -148,7 +148,7 @@ defmodule Livebook.IntellisenseTest do
|
||||||
detail: "module",
|
detail: "module",
|
||||||
documentation: "No documentation available",
|
documentation: "No documentation available",
|
||||||
insert_text: "Elixir"
|
insert_text: "Elixir"
|
||||||
} in Intellisense.get_completion_items("E", context)
|
} in Intellisense.get_completion_items("Eli", context)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "Elixir module completion" do
|
test "Elixir module completion" do
|
||||||
|
|
|
@ -377,7 +377,7 @@ defmodule Livebook.Runtime.EvaluatorTest do
|
||||||
defmodule Livebook.Runtime.EvaluatorTest.Exited do
|
defmodule Livebook.Runtime.EvaluatorTest.Exited do
|
||||||
end
|
end
|
||||||
|
|
||||||
Task.async(fn -> raise "error" end)
|
Process.exit(self(), :kill)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
{:group_leader, gl} = Process.info(evaluator.pid, :group_leader)
|
{:group_leader, gl} = Process.info(evaluator.pid, :group_leader)
|
||||||
|
|
|
@ -397,7 +397,7 @@ defmodule Livebook.SessionTest do
|
||||||
Session.set_file(session.pid, file)
|
Session.set_file(session.pid, file)
|
||||||
|
|
||||||
# Wait for the session to deal with the files
|
# Wait for the session to deal with the files
|
||||||
Process.sleep(500)
|
wait_for_session_update(session.pid)
|
||||||
|
|
||||||
assert {:ok, true} =
|
assert {:ok, true} =
|
||||||
FileSystem.File.exists?(FileSystem.File.resolve(tmp_dir, "images/test.jpg"))
|
FileSystem.File.exists?(FileSystem.File.resolve(tmp_dir, "images/test.jpg"))
|
||||||
|
@ -419,7 +419,7 @@ defmodule Livebook.SessionTest do
|
||||||
Session.set_file(session.pid, nil)
|
Session.set_file(session.pid, nil)
|
||||||
|
|
||||||
# Wait for the session to deal with the files
|
# Wait for the session to deal with the files
|
||||||
Process.sleep(500)
|
wait_for_session_update(session.pid)
|
||||||
|
|
||||||
assert {:ok, true} = FileSystem.File.exists?(image_file)
|
assert {:ok, true} = FileSystem.File.exists?(image_file)
|
||||||
|
|
||||||
|
@ -483,8 +483,6 @@ defmodule Livebook.SessionTest do
|
||||||
|
|
||||||
assert {:ok, false} = FileSystem.File.exists?(file)
|
assert {:ok, false} = FileSystem.File.exists?(file)
|
||||||
|
|
||||||
Process.flag(:trap_exit, true)
|
|
||||||
|
|
||||||
# Calling twice can happen in a race, make sure it doesn't crash
|
# Calling twice can happen in a race, make sure it doesn't crash
|
||||||
Session.close(session.pid)
|
Session.close(session.pid)
|
||||||
Session.close([session.pid])
|
Session.close([session.pid])
|
||||||
|
@ -499,11 +497,11 @@ defmodule Livebook.SessionTest do
|
||||||
|
|
||||||
assert {:ok, true} = FileSystem.File.exists?(images_dir)
|
assert {:ok, true} = FileSystem.File.exists?(images_dir)
|
||||||
|
|
||||||
Process.flag(:trap_exit, true)
|
|
||||||
Session.close(session.pid)
|
Session.close(session.pid)
|
||||||
|
|
||||||
# Wait for the session to deal with the files
|
# Wait for the session to deal with the files
|
||||||
Process.sleep(50)
|
ref = Process.monitor(session.pid)
|
||||||
|
assert_receive {:DOWN, ^ref, :process, _, _}
|
||||||
|
|
||||||
assert {:ok, false} = FileSystem.File.exists?(images_dir)
|
assert {:ok, false} = FileSystem.File.exists?(images_dir)
|
||||||
end
|
end
|
||||||
|
@ -952,4 +950,11 @@ defmodule Livebook.SessionTest do
|
||||||
{:ok, runtime} = Livebook.Runtime.NoopRuntime.new() |> Livebook.Runtime.connect()
|
{:ok, runtime} = Livebook.Runtime.NoopRuntime.new() |> Livebook.Runtime.connect()
|
||||||
runtime
|
runtime
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp wait_for_session_update(session_pid) do
|
||||||
|
# This call is synchronous, so it gives the session time
|
||||||
|
# for handling the previously sent change messages.
|
||||||
|
Session.get_data(session_pid)
|
||||||
|
:ok
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,18 +1,22 @@
|
||||||
defmodule Livebook.SessionsTest do
|
defmodule Livebook.SessionsTest do
|
||||||
use ExUnit.Case, async: true
|
use ExUnit.Case, async: true
|
||||||
|
|
||||||
alias Livebook.Sessions
|
alias Livebook.{Sessions, Session}
|
||||||
|
|
||||||
describe "create_session/0" do
|
describe "create_session/0" do
|
||||||
test "starts a new session process under the sessions supervisor" do
|
test "starts a new session process under the sessions supervisor" do
|
||||||
{:ok, session} = Sessions.create_session()
|
{:ok, session} = Sessions.create_session()
|
||||||
assert has_child_with_pid?(Livebook.SessionSupervisor, session.pid)
|
assert has_child_with_pid?(Livebook.SessionSupervisor, session.pid)
|
||||||
|
|
||||||
|
Session.close(session.pid)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "broadcasts a message to subscribers" do
|
test "broadcasts a message to subscribers" do
|
||||||
Sessions.subscribe()
|
Sessions.subscribe()
|
||||||
{:ok, %{id: id}} = Sessions.create_session()
|
{:ok, %{id: id} = session} = Sessions.create_session()
|
||||||
assert_receive {:session_created, %{id: ^id}}
|
assert_receive {:session_created, %{id: ^id}}
|
||||||
|
|
||||||
|
Session.close(session.pid)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -20,6 +24,8 @@ defmodule Livebook.SessionsTest do
|
||||||
test "lists all sessions" do
|
test "lists all sessions" do
|
||||||
{:ok, session} = Sessions.create_session()
|
{:ok, session} = Sessions.create_session()
|
||||||
assert session in Sessions.list_sessions()
|
assert session in Sessions.list_sessions()
|
||||||
|
|
||||||
|
Session.close(session.pid)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -32,6 +38,8 @@ defmodule Livebook.SessionsTest do
|
||||||
test "returns session matching the given id" do
|
test "returns session matching the given id" do
|
||||||
{:ok, session} = Sessions.create_session()
|
{:ok, session} = Sessions.create_session()
|
||||||
assert {:ok, ^session} = Sessions.fetch_session(session.id)
|
assert {:ok, ^session} = Sessions.fetch_session(session.id)
|
||||||
|
|
||||||
|
Session.close(session.pid)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -42,6 +50,8 @@ defmodule Livebook.SessionsTest do
|
||||||
updated_session = %{session | notebook_name: "New name"}
|
updated_session = %{session | notebook_name: "New name"}
|
||||||
Livebook.Sessions.update_session(updated_session)
|
Livebook.Sessions.update_session(updated_session)
|
||||||
assert_receive {:session_updated, %{id: ^id, notebook_name: "New name"}}
|
assert_receive {:session_updated, %{id: ^id, notebook_name: "New name"}}
|
||||||
|
|
||||||
|
Session.close(session.pid)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,8 @@ defmodule LivebookWeb.SessionControllerTest do
|
||||||
|
|
||||||
assert conn.status == 400
|
assert conn.status == 400
|
||||||
assert conn.resp_body == "Invalid format, supported formats: livemd, exs"
|
assert conn.resp_body == "Invalid format, supported formats: livemd, exs"
|
||||||
|
|
||||||
|
Session.close(session.pid)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "handles live markdown notebook source", %{conn: conn} do
|
test "handles live markdown notebook source", %{conn: conn} do
|
||||||
|
|
|
@ -226,8 +226,6 @@ defmodule LivebookWeb.HomeLiveTest do
|
||||||
refute render(view) =~ session1.id
|
refute render(view) =~ session1.id
|
||||||
refute render(view) =~ session2.id
|
refute render(view) =~ session2.id
|
||||||
refute render(view) =~ session3.id
|
refute render(view) =~ session3.id
|
||||||
|
|
||||||
Session.close([session1.pid, session2.pid, session3.pid])
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -15,14 +15,21 @@ defmodule LivebookWeb.LearnLiveTest do
|
||||||
|
|
||||||
{:ok, view, _} = live(conn, to)
|
{:ok, view, _} = live(conn, to)
|
||||||
assert render(view) =~ "Welcome to Livebook"
|
assert render(view) =~ "Welcome to Livebook"
|
||||||
|
|
||||||
|
close_session_by_path(to)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "link to a new notebook creates an empty session", %{conn: conn} do
|
test "link to a new notebook creates an empty session", %{conn: conn} do
|
||||||
{:ok, view, _} =
|
assert {:error, {:live_redirect, %{to: to}}} = result = live(conn, "/learn/notebooks/new")
|
||||||
conn
|
{:ok, view, _} = follow_redirect(result, conn)
|
||||||
|> live("/learn/notebooks/new")
|
|
||||||
|> follow_redirect(conn)
|
|
||||||
|
|
||||||
assert render(view) =~ "Untitled notebook"
|
assert render(view) =~ "Untitled notebook"
|
||||||
|
|
||||||
|
close_session_by_path(to)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp close_session_by_path("/sessions/" <> session_id) do
|
||||||
|
{:ok, session} = Livebook.Sessions.fetch_session(session_id)
|
||||||
|
Livebook.Session.close(session.pid)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1145,6 +1145,10 @@ defmodule LivebookWeb.SessionLiveTest do
|
||||||
@tag :tmp_dir
|
@tag :tmp_dir
|
||||||
test "outputs persisted PATH delimited with os PATH env var",
|
test "outputs persisted PATH delimited with os PATH env var",
|
||||||
%{conn: conn, session: session, tmp_dir: tmp_dir} do
|
%{conn: conn, session: session, tmp_dir: tmp_dir} do
|
||||||
|
# Start the standalone runtime, to encapsulate env var changes
|
||||||
|
{:ok, runtime} = Runtime.ElixirStandalone.new() |> Runtime.connect()
|
||||||
|
Session.set_runtime(session.pid, runtime)
|
||||||
|
|
||||||
separator =
|
separator =
|
||||||
case :os.type() do
|
case :os.type() do
|
||||||
{:win32, _} -> ";"
|
{:win32, _} -> ";"
|
||||||
|
@ -1162,17 +1166,16 @@ defmodule LivebookWeb.SessionLiveTest do
|
||||||
|
|
||||||
section_id = insert_section(session.pid)
|
section_id = insert_section(session.pid)
|
||||||
|
|
||||||
cell_id =
|
cell_id = insert_text_cell(session.pid, section_id, :code, ~s{System.get_env("PATH")})
|
||||||
insert_text_cell(session.pid, section_id, :code, ~s{System.get_env("PATH") |> IO.write()})
|
|
||||||
|
|
||||||
view
|
view
|
||||||
|> element(~s{[data-el-session]})
|
|> element(~s{[data-el-session]})
|
||||||
|> render_hook("queue_cell_evaluation", %{"cell_id" => cell_id})
|
|> render_hook("queue_cell_evaluation", %{"cell_id" => cell_id})
|
||||||
|
|
||||||
assert_receive {:operation,
|
assert_receive {:operation,
|
||||||
{:add_cell_evaluation_output, _, ^cell_id, {:stdout, ^expected_path}}}
|
{:add_cell_evaluation_response, _, ^cell_id, {:text, output}, _}}
|
||||||
|
|
||||||
assert_receive {:operation, {:add_cell_evaluation_response, _, ^cell_id, _, _}}
|
assert output == "\e[32m\"#{expected_path}\"\e[0m"
|
||||||
|
|
||||||
Settings.unset_env_var("PATH")
|
Settings.unset_env_var("PATH")
|
||||||
|
|
||||||
|
@ -1181,7 +1184,9 @@ defmodule LivebookWeb.SessionLiveTest do
|
||||||
|> render_hook("queue_cell_evaluation", %{"cell_id" => cell_id})
|
|> render_hook("queue_cell_evaluation", %{"cell_id" => cell_id})
|
||||||
|
|
||||||
assert_receive {:operation,
|
assert_receive {:operation,
|
||||||
{:add_cell_evaluation_output, _, ^cell_id, {:stdout, ^initial_os_path}}}
|
{:add_cell_evaluation_response, _, ^cell_id, {:text, output}, _}}
|
||||||
|
|
||||||
|
assert output == "\e[32m\"#{initial_os_path}\"\e[0m"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue