-
+
+ <.modal
+ :if={@show_key}
+ id="show-key-modal"
+ width={:medium}
+ show={true}
+ patch={~p"/hub/#{@hub.id}"}
+ >
+
+
+ Teams Key
+
+
+ This is your Teams Key . If you want to join or invite others
+ to your organization, you will need to share your Teams Key with them. We
+ recommend storing it somewhere safe:
+
+
+
+
-
- Delete hub
-
-
+
+
JS.add_class(
+ "tooltip top",
+ to: "#teams-key-toggle [data-copy]",
+ transition: {"ease-out duration-200", "opacity-0", "opacity-100"}
+ )
+ |> JS.remove_class(
+ "tooltip top",
+ to: "#teams-key-toggle [data-copy]",
+ transition: {"ease-out duration-200", "opacity-0", "opacity-100"},
+ time: 2000
+ )
+ }
+ >
+ <.remix_icon icon="clipboard-line" class="text-xl" />
+
-
-
-
- General
-
-
- <.form
- :let={f}
- id={@id}
- class="flex flex-col mt-4 space-y-4"
- for={@form}
- phx-submit="save"
- phx-change="validate"
- phx-target={@myself}
- >
-
- <.emoji_field field={f[:hub_emoji]} label="Emoji" />
+ JS.set_attribute({"type", "text"}, to: "#teams-key-toggle input")
+ |> JS.add_class("hidden", to: "#teams-key-toggle [data-show]")
+ |> JS.remove_class("hidden", to: "#teams-key-toggle [data-hide]")
+ }
+ >
+ <.remix_icon icon="eye-line" class="text-xl" />
+
+ JS.set_attribute({"type", "password"}, to: "#teams-key-toggle input")
+ |> JS.remove_class("hidden", to: "#teams-key-toggle [data-show]")
+ |> JS.add_class("hidden", to: "#teams-key-toggle [data-hide]")
+ }
+ >
+ <.remix_icon icon="eye-off-line" class="text-xl" />
+
+
+
+
+
-
- Update Hub
-
-
+
+
+
+
+
+ Delete hub
+
+
+
+
+
+
+ General
+
+
+ <.form
+ :let={f}
+ id={@id}
+ class="flex flex-col mt-4 space-y-4"
+ for={@form}
+ phx-submit="save"
+ phx-change="validate"
+ phx-target={@myself}
+ >
+
+ <.emoji_field field={f[:hub_emoji]} label="Emoji" />
+
+
+
+ Update Hub
+
+
+
diff --git a/lib/livebook_web/live/hub/edit_live.ex b/lib/livebook_web/live/hub/edit_live.ex
index 59c470c02..118056a84 100644
--- a/lib/livebook_web/live/hub/edit_live.ex
+++ b/lib/livebook_web/live/hub/edit_live.ex
@@ -9,32 +9,16 @@ defmodule LivebookWeb.Hub.EditLive do
@impl true
def mount(_params, _session, socket) do
- {:ok,
- assign(socket,
- hub: nil,
- secrets: [],
- type: nil,
- page_title: "Hub - Livebook",
- env_var_id: nil,
- secret_name: nil
- )}
+ {:ok, assign(socket, hub: nil, type: nil, page_title: "Hub - Livebook", params: %{})}
end
@impl true
def handle_params(params, _url, socket) do
- Livebook.Hubs.subscribe([:secrets])
+ Hubs.subscribe([:secrets])
hub = Hubs.fetch_hub!(params["id"])
type = Provider.type(hub)
- {:noreply,
- assign(socket,
- hub: hub,
- type: type,
- secrets: Hubs.get_secrets(hub),
- params: params,
- env_var_id: params["env_var_id"],
- secret_name: params["secret_name"]
- )}
+ {:noreply, assign(socket, hub: hub, type: type, params: params, counter: 0)}
end
@impl true
@@ -50,8 +34,8 @@ defmodule LivebookWeb.Hub.EditLive do
type={@type}
hub={@hub}
live_action={@live_action}
- secrets={@secrets}
- secret_name={@secret_name}
+ params={@params}
+ counter={@counter}
/>
@@ -63,16 +47,23 @@ defmodule LivebookWeb.Hub.EditLive do
<.live_component
module={LivebookWeb.Hub.Edit.PersonalComponent}
hub={@hub}
- secrets={@secrets}
+ params={@params}
live_action={@live_action}
- secret_name={@secret_name}
+ counter={@counter}
id="personal-form"
/>
"""
end
defp hub_component(%{type: "team"} = assigns) do
- ~H(<.live_component module={LivebookWeb.Hub.Edit.TeamComponent} hub={@hub} id="team-form" />)
+ ~H"""
+ <.live_component
+ module={LivebookWeb.Hub.Edit.TeamComponent}
+ hub={@hub}
+ params={@params}
+ id="team-form"
+ />
+ """
end
@impl true
@@ -98,21 +89,21 @@ defmodule LivebookWeb.Hub.EditLive do
def handle_info({:secret_created, %{hub_id: id}}, %{assigns: %{hub: %{id: id}}} = socket) do
{:noreply,
socket
- |> refresh_secrets()
+ |> increment_counter()
|> put_flash(:success, "Secret created successfully")}
end
def handle_info({:secret_updated, %{hub_id: id}}, %{assigns: %{hub: %{id: id}}} = socket) do
{:noreply,
socket
- |> refresh_secrets()
+ |> increment_counter()
|> put_flash(:success, "Secret updated successfully")}
end
def handle_info({:secret_deleted, %{hub_id: id}}, %{assigns: %{hub: %{id: id}}} = socket) do
{:noreply,
socket
- |> refresh_secrets()
+ |> increment_counter()
|> put_flash(:success, "Secret deleted successfully")}
end
@@ -120,7 +111,5 @@ defmodule LivebookWeb.Hub.EditLive do
{:noreply, socket}
end
- defp refresh_secrets(socket) do
- assign(socket, secrets: Livebook.Hubs.get_secrets(socket.assigns.hub))
- end
+ defp increment_counter(socket), do: assign(socket, counter: socket.assigns.counter + 1)
end
diff --git a/lib/livebook_web/live/hub/new_live.ex b/lib/livebook_web/live/hub/new_live.ex
index ac7a058c9..d478ab9ff 100644
--- a/lib/livebook_web/live/hub/new_live.ex
+++ b/lib/livebook_web/live/hub/new_live.ex
@@ -132,7 +132,7 @@ defmodule LivebookWeb.Hub.NewLive do
<.password_field
- readonly={@selected_option == "new-org"}
+ :if={@selected_option == "join-org"}
field={f[:teams_key]}
label="Livebook Teams Key"
/>
@@ -281,7 +281,7 @@ defmodule LivebookWeb.Hub.NewLive do
{:noreply,
socket
|> put_flash(:success, "Hub added successfully")
- |> push_navigate(to: ~p"/hub/#{hub.id}")}
+ |> push_navigate(to: ~p"/hub/#{hub.id}?show-key=true")}
{:error, :expired} ->
changeset = Teams.change_org(org, %{user_code: nil})
@@ -293,6 +293,12 @@ defmodule LivebookWeb.Hub.NewLive do
|> assign_form(changeset)}
{:transport_error, message} ->
+ Process.send_after(
+ self(),
+ {:check_completion_data, device_code},
+ @check_completion_data_interval
+ )
+
{:noreply, put_flash(socket, :error, message)}
end
end
diff --git a/test/livebook/hubs/enterprise_client_test.exs b/test/livebook/hubs/enterprise_client_test.exs
deleted file mode 100644
index 0975db338..000000000
--- a/test/livebook/hubs/enterprise_client_test.exs
+++ /dev/null
@@ -1,99 +0,0 @@
-defmodule Livebook.Hubs.EnterpriseClientTest do
- use Livebook.EnterpriseIntegrationCase, async: true
- @moduletag :capture_log
-
- alias Livebook.Hubs.EnterpriseClient
- alias Livebook.Secrets.Secret
-
- setup do
- Livebook.Hubs.subscribe([:connection, :secrets])
- :ok
- end
-
- describe "start_link/1" do
- test "successfully authenticates the web socket connection", %{url: url, token: token} do
- enterprise = build(:enterprise, url: url, token: token)
-
- EnterpriseClient.start_link(enterprise)
- assert_receive :hub_connected
- end
-
- test "rejects the websocket with invalid address", %{token: token} do
- enterprise = build(:enterprise, url: "http://localhost:9999", token: token)
-
- EnterpriseClient.start_link(enterprise)
- assert_receive {:hub_connection_failed, "connection refused"}
- end
-
- test "rejects the web socket connection with invalid credentials", %{url: url} do
- enterprise = build(:enterprise, url: url, token: "foo")
-
- EnterpriseClient.start_link(enterprise)
- assert_receive {:hub_connection_failed, reason}
- assert reason =~ "the given token is invalid"
- end
- end
-
- describe "handle events" do
- setup %{test: test, url: url, token: token} do
- node = EnterpriseServer.get_node()
- hub_id = "enterprise-#{test}"
-
- insert_hub(:enterprise,
- id: hub_id,
- external_id: to_string(test),
- url: url,
- token: token
- )
-
- assert_receive :hub_connected
-
- {:ok, node: node, hub_id: hub_id}
- end
-
- test "receives a secret_created event", %{node: node, hub_id: id} do
- name = "API_TOKEN_ID"
- value = Livebook.Utils.random_id()
- :erpc.call(node, Enterprise.Integration, :create_secret, [name, value])
- secret = %Secret{name: name, value: value, hub_id: id, readonly: true}
-
- assert_receive {:secret_created, ^secret}
- assert secret in EnterpriseClient.get_secrets(id)
- end
-
- test "receives a secret_updated event", %{node: node, hub_id: id} do
- name = "SUPER_SUDO_USER"
- value = "JakePeralta"
- new_value = "ChonkyCat"
- enterprise_secret = :erpc.call(node, Enterprise.Integration, :create_secret, [name, value])
- secret = %Secret{name: name, value: value, hub_id: id, readonly: true}
- updated_secret = %Secret{name: name, value: new_value, hub_id: id, readonly: true}
-
- assert_receive {:secret_created, ^secret}
- assert secret in EnterpriseClient.get_secrets(id)
- refute updated_secret in EnterpriseClient.get_secrets(id)
-
- :erpc.call(node, Enterprise.Integration, :update_secret, [enterprise_secret, new_value])
-
- assert_receive {:secret_updated, ^updated_secret}
-
- assert updated_secret in EnterpriseClient.get_secrets(id)
- refute secret in EnterpriseClient.get_secrets(id)
- end
-
- test "receives a secret_deleted event", %{node: node, hub_id: id} do
- name = "SUPER_DELETE"
- value = "JakePeralta"
- enteprise_secret = :erpc.call(node, Enterprise.Integration, :create_secret, [name, value])
- secret = %Secret{name: name, value: value, hub_id: id, readonly: true}
-
- assert_receive {:secret_created, ^secret}
- assert secret in EnterpriseClient.get_secrets(id)
-
- :erpc.call(node, Enterprise.Integration, :delete_secret, [enteprise_secret])
-
- assert_receive {:secret_deleted, ^secret}
- refute secret in EnterpriseClient.get_secrets(id)
- end
- end
-end
diff --git a/test/livebook/hubs/fly_client_test.exs b/test/livebook/hubs/fly_client_test.exs
deleted file mode 100644
index 64e68135b..000000000
--- a/test/livebook/hubs/fly_client_test.exs
+++ /dev/null
@@ -1,225 +0,0 @@
-defmodule Livebook.Hubs.FlyClientTest do
- use Livebook.DataCase
-
- alias Livebook.Hubs.{Fly, FlyClient}
-
- setup do
- bypass = Bypass.open()
-
- Application.put_env(
- :livebook,
- :fly_graphql_endpoint,
- "http://localhost:#{bypass.port}"
- )
-
- on_exit(fn ->
- Application.delete_env(:livebook, :fly_graphql_endpoint)
- end)
-
- {:ok, bypass: bypass, url: "http://localhost:#{bypass.port}"}
- end
-
- describe "fetch_apps/1" do
- test "fetches an empty list of apps", %{bypass: bypass} do
- response = %{"data" => %{"apps" => %{"nodes" => []}}}
-
- Bypass.expect_once(bypass, "POST", "/", fn conn ->
- conn
- |> Plug.Conn.put_resp_content_type("application/json")
- |> Plug.Conn.resp(200, Jason.encode!(response))
- end)
-
- assert {:ok, []} = FlyClient.fetch_apps("some valid token")
- end
-
- test "fetches a list of apps", %{bypass: bypass} do
- app = %{
- "id" => "foo-app",
- "organization" => %{
- "id" => "l3soyvjmvtmwtl6l2drnbfuvltipprge",
- "name" => "Foo Bar",
- "type" => "PERSONAL"
- }
- }
-
- app_id = app["id"]
-
- response = %{"data" => %{"apps" => %{"nodes" => [app]}}}
-
- Bypass.expect_once(bypass, "POST", "/", fn conn ->
- conn
- |> Plug.Conn.put_resp_content_type("application/json")
- |> Plug.Conn.resp(200, Jason.encode!(response))
- end)
-
- assert {:ok, [%Fly{application_id: ^app_id}]} = FlyClient.fetch_apps("some valid token")
- end
-
- test "returns unauthorized when token is invalid", %{bypass: bypass} do
- error = %{"extensions" => %{"code" => "UNAUTHORIZED"}}
- response = %{"data" => nil, "errors" => [error]}
-
- Bypass.expect_once(bypass, "POST", "/", fn conn ->
- conn
- |> Plug.Conn.put_resp_content_type("application/json")
- |> Plug.Conn.resp(200, Jason.encode!(response))
- end)
-
- assert {:error, "request failed with code: UNAUTHORIZED"} = FlyClient.fetch_apps("foo")
- end
- end
-
- describe "fetch_app/1" do
- test "fetches an application", %{bypass: bypass} do
- app = %{
- "id" => "foo-app",
- "name" => "foo-app",
- "hostname" => "foo-app.fly.dev",
- "platformVersion" => "nomad",
- "deployed" => true,
- "status" => "running",
- "secrets" => [
- %{
- "createdAt" => to_string(DateTime.utc_now()),
- "digest" => to_string(Livebook.Utils.random_cookie()),
- "id" => Livebook.Utils.random_short_id(),
- "name" => "FOO"
- }
- ]
- }
-
- response = %{"data" => %{"app" => app}}
-
- Bypass.expect_once(bypass, "POST", "/", fn conn ->
- conn
- |> Plug.Conn.put_resp_content_type("application/json")
- |> Plug.Conn.resp(200, Jason.encode!(response))
- end)
-
- hub = build(:fly)
- assert {:ok, ^app} = FlyClient.fetch_app(hub)
- end
-
- test "returns unauthorized when token is invalid", %{bypass: bypass} do
- error = %{"extensions" => %{"code" => "UNAUTHORIZED"}}
- response = %{"data" => nil, "errors" => [error]}
-
- Bypass.expect_once(bypass, "POST", "/", fn conn ->
- conn
- |> Plug.Conn.put_resp_content_type("application/json")
- |> Plug.Conn.resp(200, Jason.encode!(response))
- end)
-
- hub = build(:fly)
- assert {:error, "request failed with code: UNAUTHORIZED"} = FlyClient.fetch_app(hub)
- end
- end
-
- describe "set_secrets/2" do
- test "puts a list of secrets inside application", %{bypass: bypass} do
- secrets = [
- %{
- "createdAt" => to_string(DateTime.utc_now()),
- "digest" => to_string(Livebook.Utils.random_cookie()),
- "id" => Livebook.Utils.random_short_id(),
- "name" => "FOO"
- }
- ]
-
- response = %{"data" => %{"setSecrets" => %{"app" => %{"secrets" => secrets}}}}
-
- Bypass.expect_once(bypass, "POST", "/", fn conn ->
- conn
- |> Plug.Conn.put_resp_content_type("application/json")
- |> Plug.Conn.resp(200, Jason.encode!(response))
- end)
-
- hub = build(:fly)
- assert {:ok, ^secrets} = FlyClient.set_secrets(hub, [%{key: "FOO", value: "BAR"}])
- end
-
- test "returns error when input is invalid", %{bypass: bypass} do
- message =
- "Variable $input of type SetSecretsInput! was provided invalid value for secrets.0.Value (Field is not defined on SecretInput), secrets.0.value (Expected value to not be null)"
-
- error = %{
- "extensions" => %{
- "problems" => [
- %{
- "explanation" => "Field is not defined on SecretInput",
- "path" => ["secrets", 0, "Value"]
- },
- %{
- "explanation" => "Expected value to not be null",
- "path" => ["secrets", 0, "value"]
- }
- ],
- "value" => %{
- "appId" => "myfoo-test-livebook",
- "secrets" => [%{"Value" => "BAR", "key" => "FOO"}]
- }
- },
- "locations" => [%{"column" => 10, "line" => 1}],
- "message" => message
- }
-
- response = %{"data" => nil, "errors" => [error]}
-
- Bypass.expect_once(bypass, "POST", "/", fn conn ->
- conn
- |> Plug.Conn.put_resp_content_type("application/json")
- |> Plug.Conn.resp(200, Jason.encode!(response))
- end)
-
- hub = build(:fly)
- assert {:error, ^message} = FlyClient.set_secrets(hub, [%{key: "FOO", Value: "BAR"}])
- end
-
- test "returns unauthorized when token is invalid", %{bypass: bypass} do
- error = %{"extensions" => %{"code" => "UNAUTHORIZED"}}
- response = %{"data" => nil, "errors" => [error]}
-
- Bypass.expect_once(bypass, "POST", "/", fn conn ->
- conn
- |> Plug.Conn.put_resp_content_type("application/json")
- |> Plug.Conn.resp(200, Jason.encode!(response))
- end)
-
- hub = build(:fly)
-
- assert {:error, "request failed with code: UNAUTHORIZED"} =
- FlyClient.set_secrets(hub, [%{key: "FOO", value: "BAR"}])
- end
- end
-
- describe "unset_secrets/2" do
- test "deletes a list of secrets inside application", %{bypass: bypass} do
- response = %{"data" => %{"unsetSecrets" => %{"app" => %{"secrets" => []}}}}
-
- Bypass.expect_once(bypass, "POST", "/", fn conn ->
- conn
- |> Plug.Conn.put_resp_content_type("application/json")
- |> Plug.Conn.resp(200, Jason.encode!(response))
- end)
-
- hub = build(:fly)
- assert {:ok, []} = FlyClient.unset_secrets(hub, ["FOO"])
- end
-
- test "returns unauthorized when token is invalid", %{bypass: bypass} do
- error = %{"extensions" => %{"code" => "UNAUTHORIZED"}}
- response = %{"data" => nil, "errors" => [error]}
-
- Bypass.expect_once(bypass, "POST", "/", fn conn ->
- conn
- |> Plug.Conn.put_resp_content_type("application/json")
- |> Plug.Conn.resp(200, Jason.encode!(response))
- end)
-
- hub = build(:fly)
-
- assert {:error, "request failed with code: UNAUTHORIZED"} =
- FlyClient.unset_secrets(hub, ["FOO"])
- end
- end
-end
diff --git a/test/livebook/hubs_test.exs b/test/livebook/hubs_test.exs
index 495f06d63..0e69bb531 100644
--- a/test/livebook/hubs_test.exs
+++ b/test/livebook/hubs_test.exs
@@ -4,53 +4,53 @@ defmodule Livebook.HubsTest do
alias Livebook.Hubs
test "get_hubs/0 returns a list of persisted hubs" do
- fly = insert_hub(:fly, id: "fly-baz")
- assert fly in Hubs.get_hubs()
+ team = insert_hub(:team, id: "team-baz")
+ assert team in Hubs.get_hubs()
- Hubs.delete_hub("fly-baz")
- refute fly in Hubs.get_hubs()
+ Hubs.delete_hub("team-baz")
+ refute team in Hubs.get_hubs()
end
test "get_metadata/0 returns a list of persisted hubs normalized" do
- fly = insert_hub(:fly, id: "fly-livebook")
- metadata = Hubs.Provider.to_metadata(fly)
+ team = insert_hub(:team, id: "team-livebook")
+ metadata = Hubs.Provider.to_metadata(team)
assert metadata in Hubs.get_metadatas()
- Hubs.delete_hub("fly-livebook")
+ Hubs.delete_hub("team-livebook")
refute metadata in Hubs.get_metadatas()
end
- test "fetch_hub!/1 returns one persisted fly" do
+ test "fetch_hub!/1 returns one persisted team" do
assert_raise Livebook.Storage.NotFoundError,
- ~s/could not find entry in \"hubs\" with ID "fly-exception-foo"/,
+ ~s/could not find entry in \"hubs\" with ID "team-exception-foo"/,
fn ->
- Hubs.fetch_hub!("fly-exception-foo")
+ Hubs.fetch_hub!("team-exception-foo")
end
- fly = insert_hub(:fly, id: "fly-exception-foo")
+ team = insert_hub(:team, id: "team-exception-foo")
- assert Hubs.fetch_hub!("fly-exception-foo") == fly
+ assert Hubs.fetch_hub!("team-exception-foo") == team
end
test "hub_exists?/1" do
- refute Hubs.hub_exists?("fly-bar")
- insert_hub(:fly, id: "fly-bar")
- assert Hubs.hub_exists?("fly-bar")
+ refute Hubs.hub_exists?("team-bar")
+ insert_hub(:team, id: "team-bar")
+ assert Hubs.hub_exists?("team-bar")
end
test "save_hub/1 persists hub" do
- fly = build(:fly, id: "fly-foo")
- Hubs.save_hub(fly)
+ team = build(:team, id: "team-foo")
+ Hubs.save_hub(team)
- assert Hubs.fetch_hub!("fly-foo") == fly
+ assert Hubs.fetch_hub!("team-foo") == team
end
test "save_hub/1 updates hub" do
- fly = insert_hub(:fly, id: "fly-foo2")
- Hubs.save_hub(%{fly | hub_emoji: "🐈"})
+ team = insert_hub(:team, id: "team-foo2")
+ Hubs.save_hub(%{team | hub_emoji: "🐈"})
- refute Hubs.fetch_hub!("fly-foo2") == fly
- assert Hubs.fetch_hub!("fly-foo2").hub_emoji == "🐈"
+ refute Hubs.fetch_hub!("team-foo2") == team
+ assert Hubs.fetch_hub!("team-foo2").hub_emoji == "🐈"
end
end
diff --git a/test/livebook/hubs/docs_test.exs b/test/livebook/intellisense/docs_test.exs
similarity index 100%
rename from test/livebook/hubs/docs_test.exs
rename to test/livebook/intellisense/docs_test.exs
diff --git a/test/livebook/live_markdown/export_test.exs b/test/livebook/live_markdown/export_test.exs
index 589f8605b..5ea1ec4bb 100644
--- a/test/livebook/live_markdown/export_test.exs
+++ b/test/livebook/live_markdown/export_test.exs
@@ -1122,16 +1122,16 @@ defmodule Livebook.LiveMarkdown.ExportTest do
end
test "persists hub id when not default" do
- Livebook.Factory.insert_hub(:fly, id: "fly-persisted-id")
+ Livebook.Factory.insert_hub(:team, id: "team-persisted-id")
notebook = %{
Notebook.new()
| name: "My Notebook",
- hub_id: "fly-persisted-id"
+ hub_id: "team-persisted-id"
}
expected_document = """
-
+
# My Notebook
"""
diff --git a/test/livebook/live_markdown/import_test.exs b/test/livebook/live_markdown/import_test.exs
index 769c1ab93..e08493e46 100644
--- a/test/livebook/live_markdown/import_test.exs
+++ b/test/livebook/live_markdown/import_test.exs
@@ -721,17 +721,17 @@ defmodule Livebook.LiveMarkdown.ImportTest do
end
test "imports notebook hub id when exists" do
- Livebook.Factory.insert_hub(:fly, id: "fly-persisted-id")
+ Livebook.Factory.insert_hub(:team, id: "team-persisted-id")
markdown = """
-
+
# My Notebook
"""
{notebook, []} = Import.notebook_from_livemd(markdown)
- assert %Notebook{name: "My Notebook", hub_id: "fly-persisted-id"} = notebook
+ assert %Notebook{name: "My Notebook", hub_id: "team-persisted-id"} = notebook
end
test "imports ignores hub id when does not exist" do
diff --git a/test/livebook/teams_test.exs b/test/livebook/teams_test.exs
index 410dd78cb..ad04045c1 100644
--- a/test/livebook/teams_test.exs
+++ b/test/livebook/teams_test.exs
@@ -78,12 +78,14 @@ defmodule Livebook.TeamsTest do
)
%{
- org: %{id: id, name: name, keys: [%{id: org_key_id}]},
- user: %{id: user_id},
- sessions: [%{token: token}]
- } = org_request.user_org
+ token: token,
+ user_org: %{
+ org: %{id: id, name: name, keys: [%{id: org_key_id}]},
+ user: %{id: user_id}
+ }
+ } = org_request.user_org_session
- assert Teams.get_org_request_completion_data(org) ==
+ assert Teams.get_org_request_completion_data(org, org_request.device_code) ==
{:ok,
%{
"id" => id,
@@ -108,12 +110,13 @@ defmodule Livebook.TeamsTest do
user_code: org_request.user_code
)
- assert Teams.get_org_request_completion_data(org) == {:ok, :awaiting_confirmation}
+ assert Teams.get_org_request_completion_data(org, org_request.device_code) ==
+ {:ok, :awaiting_confirmation}
end
test "returns error when org request doesn't exist" do
org = build(:org, id: 0)
- assert {:transport_error, _embarrassing} = Teams.get_org_request_completion_data(org)
+ assert {:transport_error, _embarrassing} = Teams.get_org_request_completion_data(org, "")
end
test "returns error when org request expired", %{node: node} do
@@ -135,7 +138,8 @@ defmodule Livebook.TeamsTest do
user_code: org_request.user_code
)
- assert Teams.get_org_request_completion_data(org) == {:error, :expired}
+ assert Teams.get_org_request_completion_data(org, org_request.device_code) ==
+ {:error, :expired}
end
end
end
diff --git a/test/livebook/web_socket/client_connection_test.exs b/test/livebook/web_socket/client_connection_test.exs
deleted file mode 100644
index 2d69cdac1..000000000
--- a/test/livebook/web_socket/client_connection_test.exs
+++ /dev/null
@@ -1,168 +0,0 @@
-defmodule Livebook.WebSocket.ClientConnectionTest do
- use Livebook.EnterpriseIntegrationCase, async: true
-
- @moduletag :capture_log
-
- alias Livebook.WebSocket.ClientConnection
-
- describe "connect" do
- test "successfully authenticates the websocket connection", %{url: url, token: token} do
- headers = [{"X-Auth-Token", token}]
-
- assert {:ok, _conn} = ClientConnection.start_link(self(), url, headers)
- assert_receive {:connect, :ok, :connected}
- end
-
- test "rejects the websocket with invalid address", %{token: token} do
- headers = [{"X-Auth-Token", token}]
-
- assert {:ok, _conn} = ClientConnection.start_link(self(), "http://localhost:9999", headers)
- assert_receive {:connect, :error, "connection refused"}
- end
-
- test "rejects the websocket connection with invalid credentials", %{url: url} do
- headers = [{"X-Auth-Token", "foo"}]
-
- assert {:ok, _conn} = ClientConnection.start_link(self(), url, headers)
-
- assert_receive {:connect, :error, reason}
- assert reason =~ "the given token is invalid"
-
- assert {:ok, _conn} = ClientConnection.start_link(self(), url)
-
- assert_receive {:connect, :error, reason}
- assert reason =~ "could not get the token from the connection"
- end
- end
-
- describe "send_request/2" do
- setup %{url: url, token: token} do
- headers = [{"X-Auth-Token", token}]
-
- {:ok, conn} = ClientConnection.start_link(self(), url, headers)
- assert_receive {:connect, :ok, :connected}
-
- {:ok, conn: conn}
- end
-
- test "successfully sends a session request", %{conn: conn, user: %{id: id, email: email}} do
- data = LivebookProto.build_handshake_request(app_version: Livebook.Config.app_version())
-
- assert {:handshake, handshake_response} = ClientConnection.send_request(conn, data)
- assert %{id: _, user: %{id: ^id, email: ^email}} = handshake_response
- end
-
- test "successfully sends a create secret message", %{conn: conn} do
- data = LivebookProto.build_create_secret_request(name: "MY_USERNAME", value: "Jake Peralta")
- assert {:create_secret, _} = ClientConnection.send_request(conn, data)
- end
-
- test "sends a create secret message, but receive a changeset error", %{conn: conn} do
- data = LivebookProto.build_create_secret_request(name: "MY_USERNAME", value: "")
- assert {:changeset_error, errors} = ClientConnection.send_request(conn, data)
- assert "can't be blank" in errors.value
- end
- end
-
- describe "reconnect event" do
- setup %{test: name} do
- start_new_instance(name)
-
- url = EnterpriseServer.url(name)
- token = EnterpriseServer.token(name)
- headers = [{"X-Auth-Token", token}]
-
- assert {:ok, conn} = ClientConnection.start_link(self(), url, headers)
- assert_receive {:connect, :ok, :connected}
-
- on_exit(fn -> stop_new_instance(name) end)
-
- {:ok, conn: conn}
- end
-
- test "receives the disconnect message from websocket server", %{conn: conn, test: name} do
- EnterpriseServer.disconnect(name)
-
- assert_receive {:connect, :error, "socket closed"}
- assert_receive {:connect, :error, "connection refused"}
-
- assert Process.alive?(conn)
- end
-
- test "reconnects after websocket server is up", %{test: name} do
- EnterpriseServer.disconnect(name)
-
- assert_receive {:connect, :error, "socket closed"}
- assert_receive {:connect, :error, "connection refused"}
-
- Process.sleep(1000)
-
- # Wait until the server is up again
- assert EnterpriseServer.reconnect(name) == :ok
-
- assert_receive {:connect, :ok, :connected}, 5000
- end
- end
-
- describe "handle events from server" do
- setup %{url: url, token: token} do
- headers = [{"X-Auth-Token", token}]
-
- {:ok, conn} = ClientConnection.start_link(self(), url, headers)
- assert_receive {:connect, :ok, :connected}
-
- {:ok, conn: conn}
- end
-
- test "receives a secret_created event", %{node: node} do
- name = "MY_SECRET_ID"
- value = Livebook.Utils.random_id()
- :erpc.call(node, Enterprise.Integration, :create_secret, [name, value])
-
- assert_receive {:event, :secret_created, %{name: ^name, value: ^value}}
- end
-
- test "receives a secret_updated event", %{node: node} do
- name = "API_USERNAME"
- value = "JakePeralta"
- secret = :erpc.call(node, Enterprise.Integration, :create_secret, [name, value])
-
- assert_receive {:event, :secret_created, %{name: ^name, value: ^value}}
-
- new_value = "ChonkyCat"
- :erpc.call(node, Enterprise.Integration, :update_secret, [secret, new_value])
-
- assert_receive {:event, :secret_updated, %{name: ^name, value: ^new_value}}
- end
-
- test "receives a secret_deleted event", %{node: node} do
- name = "DELETE_ME"
- value = "JakePeralta"
- secret = :erpc.call(node, Enterprise.Integration, :create_secret, [name, value])
-
- assert_receive {:event, :secret_created, %{name: ^name, value: ^value}}
-
- :erpc.call(node, Enterprise.Integration, :delete_secret, [secret])
-
- assert_receive {:event, :secret_deleted, %{name: ^name, value: ^value}}
- end
-
- test "receives a user_synchronized event", %{conn: conn, node: node} do
- data = LivebookProto.build_handshake_request(app_version: Livebook.Config.app_version())
- assert {:handshake, _} = ClientConnection.send_request(conn, data)
-
- id = :erpc.call(node, Enterprise.Integration, :fetch_env!, ["ENTERPRISE_ID"])
- name = :erpc.call(node, Enterprise.Integration, :fetch_env!, ["ENTERPRISE_NAME"])
-
- assert_receive {:event, :user_synchronized, %{id: ^id, name: ^name, secrets: []}}
-
- secret = :erpc.call(node, Enterprise.Integration, :create_secret, ["SESSION", "123"])
- assert_receive {:event, :secret_created, %{name: "SESSION", value: "123"}}
-
- assert {:handshake, _} = ClientConnection.send_request(conn, data)
-
- assert_receive {:event, :user_synchronized, %{id: ^id, name: ^name, secrets: secrets}}
- assert LivebookProto.Secret.new!(name: secret.name, value: secret.value) in secrets
- end
- end
-end
diff --git a/test/livebook_web/live/home_live_test.exs b/test/livebook_web/live/home_live_test.exs
index 4126d97cd..8782d1b6f 100644
--- a/test/livebook_web/live/home_live_test.exs
+++ b/test/livebook_web/live/home_live_test.exs
@@ -206,13 +206,13 @@ defmodule LivebookWeb.HomeLiveTest do
end
test "render persisted hubs", %{conn: conn} do
- fly = insert_hub(:fly, id: "fly-foo-bar-id")
+ team = insert_hub(:team, id: "team-foo-bar-id")
{:ok, _view, html} = live(conn, ~p"/")
assert html =~ "HUBS"
- assert html =~ fly.hub_name
+ assert html =~ team.hub_name
- Livebook.Hubs.delete_hub("fly-foo-bar-id")
+ Livebook.Hubs.delete_hub("team-foo-bar-id")
end
end
diff --git a/test/livebook_web/live/hub/edit_live_test.exs b/test/livebook_web/live/hub/edit_live_test.exs
index b3ec61044..d97dbacba 100644
--- a/test/livebook_web/live/hub/edit_live_test.exs
+++ b/test/livebook_web/live/hub/edit_live_test.exs
@@ -71,15 +71,17 @@ defmodule LivebookWeb.Hub.EditLiveTest do
|> render_submit(attrs)
assert_receive {:secret_created, ^secret}
+ assert_patch(view, "/hub/#{hub.id}")
assert render(view) =~ "Secret created successfully"
- assert render(view) =~ secret.name
+ assert render(element(view, "#hub-secrets-list")) =~ secret.name
assert secret in Livebook.Hubs.get_secrets(hub)
end
test "updates secret", %{conn: conn, hub: hub} do
- {:ok, view, _html} = live(conn, ~p"/hub/#{hub.id}")
secret = insert_secret(name: "PERSONAL_EDIT_SECRET", value: "GetTheBonk")
+ {:ok, view, _html} = live(conn, ~p"/hub/#{hub.id}")
+
attrs = %{
secret: %{
name: secret.name,
@@ -112,15 +114,17 @@ defmodule LivebookWeb.Hub.EditLiveTest do
updated_secret = %{secret | value: new_value}
assert_receive {:secret_updated, ^updated_secret}
+ assert_patch(view, "/hub/#{hub.id}")
assert render(view) =~ "Secret updated successfully"
- assert render(view) =~ secret.name
+ assert render(element(view, "#hub-secrets-list")) =~ secret.name
assert updated_secret in Livebook.Hubs.get_secrets(hub)
end
test "deletes secret", %{conn: conn, hub: hub} do
- {:ok, view, _html} = live(conn, ~p"/hub/#{hub.id}")
secret = insert_secret(name: "PERSONAL_DELETE_SECRET", value: "GetTheBonk")
+ {:ok, view, _html} = live(conn, ~p"/hub/#{hub.id}")
+
refute view
|> element("#secrets-form button[disabled]")
|> has_element?()
diff --git a/test/livebook_web/live/hub/new/enterprise_component_test.exs b/test/livebook_web/live/hub/new/enterprise_component_test.exs
deleted file mode 100644
index 6d185a5b3..000000000
--- a/test/livebook_web/live/hub/new/enterprise_component_test.exs
+++ /dev/null
@@ -1,168 +0,0 @@
-defmodule LivebookWeb.Hub.New.EnterpriseComponentTest do
- use Livebook.EnterpriseIntegrationCase, async: true
- @moduletag :capture_log
-
- import Phoenix.LiveViewTest
-
- alias Livebook.Hubs
-
- describe "enterprise" do
- test "persists new hub", %{conn: conn, url: url, token: token} do
- node = EnterpriseServer.get_node()
- id = :erpc.call(node, Enterprise.Integration, :fetch_env!, ["ENTERPRISE_ID"])
- Livebook.Hubs.delete_hub("enterprise-#{id}")
-
- {:ok, view, _html} = live(conn, ~p"/hub")
-
- assert view
- |> element("#enterprise")
- |> render_click() =~ "2. Configure your Hub"
-
- view
- |> element("#enterprise-form")
- |> render_change(%{
- "enterprise" => %{
- "url" => url,
- "token" => token
- }
- })
-
- view
- |> element("#connect")
- |> render_click()
-
- assert render(view) =~ to_string(id)
-
- attrs = %{
- "url" => url,
- "token" => token,
- "hub_name" => "Enterprise",
- "hub_emoji" => "🐈"
- }
-
- view
- |> element("#enterprise-form")
- |> render_change(%{"enterprise" => attrs})
-
- refute view
- |> element("#enterprise-form .invalid-feedback")
- |> has_element?()
-
- result =
- view
- |> element("#enterprise-form")
- |> render_submit(%{"enterprise" => attrs})
-
- assert {:ok, view, _html} = follow_redirect(result, conn)
-
- assert render(view) =~ "Hub added successfully"
-
- hubs_html = view |> element("#hubs") |> render()
- assert hubs_html =~ "🐈"
- assert hubs_html =~ "/hub/enterprise-#{id}"
- assert hubs_html =~ "Enterprise"
- end
-
- test "fails with invalid token", %{test: name, conn: conn} do
- start_new_instance(name)
-
- url = EnterpriseServer.url(name)
-
- {:ok, view, _html} = live(conn, ~p"/hub")
- token = "foo bar baz"
-
- assert view
- |> element("#enterprise")
- |> render_click() =~ "2. Configure your Hub"
-
- view
- |> element("#enterprise-form")
- |> render_change(%{
- "enterprise" => %{
- "url" => url,
- "token" => token
- }
- })
-
- view
- |> element("#connect")
- |> render_click()
-
- assert render(view) =~ "the given token is invalid"
- refute render(view) =~ "enterprise[hub_name]"
- after
- stop_new_instance(name)
- end
-
- test "fails to create existing hub", %{test: name, conn: conn} do
- start_new_instance(name)
-
- node = EnterpriseServer.get_node(name)
- url = EnterpriseServer.url(name)
- token = EnterpriseServer.token(name)
-
- id = :erpc.call(node, Enterprise.Integration, :fetch_env!, ["ENTERPRISE_ID"])
- user = :erpc.call(node, Enterprise.Integration, :create_user, [])
-
- another_token =
- :erpc.call(node, Enterprise.Integration, :generate_user_session_token!, [user])
-
- hub =
- insert_hub(:enterprise,
- id: "enterprise-#{id}",
- external_id: id,
- url: url,
- token: another_token
- )
-
- {:ok, view, _html} = live(conn, ~p"/hub")
-
- assert view
- |> element("#enterprise")
- |> render_click() =~ "2. Configure your Hub"
-
- view
- |> element("#enterprise-form")
- |> render_change(%{
- "enterprise" => %{
- "url" => url,
- "token" => token
- }
- })
-
- view
- |> element("#connect")
- |> render_click()
-
- assert render(view) =~ to_string(id)
-
- attrs = %{
- "url" => url,
- "token" => token,
- "hub_name" => "Enterprise",
- "hub_emoji" => "🐈"
- }
-
- view
- |> element("#enterprise-form")
- |> render_change(%{"enterprise" => attrs})
-
- refute view
- |> element("#enterprise-form .invalid-feedback")
- |> has_element?()
-
- assert view
- |> element("#enterprise-form")
- |> render_submit(%{"enterprise" => attrs}) =~ "already exists"
-
- hubs_html = view |> element("#hubs") |> render()
- assert hubs_html =~ hub.hub_emoji
- assert hubs_html =~ ~p"/hub/#{hub.id}"
- assert hubs_html =~ hub.hub_name
-
- assert Hubs.fetch_hub!(hub.id) == hub
- after
- stop_new_instance(name)
- end
- end
-end
diff --git a/test/livebook_web/live/hub/new_live_test.exs b/test/livebook_web/live/hub/new_live_test.exs
index a3df892df..9656008b6 100644
--- a/test/livebook_web/live/hub/new_live_test.exs
+++ b/test/livebook_web/live/hub/new_live_test.exs
@@ -4,7 +4,6 @@ defmodule LivebookWeb.Hub.NewLiveTest do
alias Livebook.Teams.Org
import Phoenix.LiveViewTest
- @check_completion_data_interval 5000
test "render hub selection cards", %{conn: conn} do
{:ok, view, _html} = live(conn, ~p"/hub")
@@ -17,9 +16,6 @@ defmodule LivebookWeb.Hub.NewLiveTest do
describe "new-org" do
test "persist a new hub", %{conn: conn, node: node, user: user} do
name = "new-org-test"
- teams_key = Livebook.Teams.Org.teams_key()
- key_hash = Org.key_hash(build(:org, teams_key: teams_key))
- path = ~p"/hub/team-#{name}"
{:ok, view, _html} = live(conn, ~p"/hub")
@@ -29,7 +25,7 @@ defmodule LivebookWeb.Hub.NewLiveTest do
|> render_click()
# builds the form data
- attrs = %{"org" => %{"name" => name, "teams_key" => teams_key, "emoji" => "🐈"}}
+ attrs = %{"org" => %{"name" => name, "emoji" => "🐈"}}
# finds the form and change data
form = element(view, "#new-org-form")
@@ -38,11 +34,8 @@ defmodule LivebookWeb.Hub.NewLiveTest do
# submits the form
render_submit(form, attrs)
- # gets the org request by name and key hash
- org_request =
- :erpc.call(node, Hub.Integration, :get_org_request_by!, [
- [name: name, key_hash: key_hash]
- ])
+ # gets the org request by name
+ org_request = :erpc.call(node, Hub.Integration, :get_org_request_by!, [[name: name]])
# check if the form has the url to confirm
link_element = element(view, "#new-org-form a")
@@ -55,14 +48,18 @@ defmodule LivebookWeb.Hub.NewLiveTest do
# check if the page redirected to edit hub page
# and check the flash message
%{"success" => "Hub added successfully"} =
- assert_redirect(view, path, @check_completion_data_interval)
+ assert_redirect(view, "/hub/team-#{name}?show-key=true", check_completion_data_interval())
+
+ # access the page and shows the teams key modal
+ {:ok, view, _html} = live(conn, "/hub/team-#{name}?show-key=true")
+ assert has_element?(view, "#show-key-modal")
+
+ # access the page when closes the modal
+ assert {:ok, view, _html} = live(conn, "/hub/team-#{name}")
+ refute has_element?(view, "#show-key-modal")
# checks if the hub is in the sidebar
- {:ok, view, _html} = live(conn, path)
- hubs_html = view |> element("#hubs") |> render()
- assert hubs_html =~ "🐈"
- assert hubs_html =~ path
- assert hubs_html =~ name
+ assert_hub(view, "/hub/team-#{name}", name)
end
end
@@ -71,7 +68,6 @@ defmodule LivebookWeb.Hub.NewLiveTest do
name = "join-org-test"
teams_key = Livebook.Teams.Org.teams_key()
key_hash = Org.key_hash(build(:org, teams_key: teams_key))
- path = ~p"/hub/team-#{name}"
{:ok, view, _html} = live(conn, ~p"/hub")
@@ -112,14 +108,28 @@ defmodule LivebookWeb.Hub.NewLiveTest do
# check if the page redirected to edit hub page
# and check the flash message
%{"success" => "Hub added successfully"} =
- assert_redirect(view, path, @check_completion_data_interval)
+ assert_redirect(view, "/hub/team-#{name}?show-key=true", check_completion_data_interval())
+
+ # access the page and shows the teams key modal
+ {:ok, view, _html} = live(conn, "/hub/team-#{name}?show-key=true")
+ assert has_element?(view, "#show-key-modal")
+
+ # access the page when closes the modal
+ assert {:ok, view, _html} = live(conn, "/hub/team-#{name}")
+ refute has_element?(view, "#show-key-modal")
# checks if the hub is in the sidebar
- {:ok, view, _html} = live(conn, path)
- hubs_html = view |> element("#hubs") |> render()
- assert hubs_html =~ "🐈"
- assert hubs_html =~ path
- assert hubs_html =~ name
+ assert_hub(view, "/hub/team-#{name}", name)
end
end
+
+ defp check_completion_data_interval(), do: 2000
+
+ defp assert_hub(view, path, name, emoji \\ "🐈") do
+ hubs_html = view |> element("#hubs") |> render()
+
+ assert hubs_html =~ emoji
+ assert hubs_html =~ path
+ assert hubs_html =~ name
+ end
end
diff --git a/test/livebook_web/live/session_live/secrets_component_test.exs b/test/livebook_web/live/session_live/secrets_component_test.exs
deleted file mode 100644
index a385e0a84..000000000
--- a/test/livebook_web/live/session_live/secrets_component_test.exs
+++ /dev/null
@@ -1,200 +0,0 @@
-defmodule LivebookWeb.SessionLive.SecretsComponentTest do
- use Livebook.EnterpriseIntegrationCase, async: true
-
- import Livebook.SessionHelpers
- import Phoenix.LiveViewTest
-
- alias Livebook.Session
- alias Livebook.Sessions
-
- describe "enterprise" do
- setup %{test: name} do
- start_new_instance(name)
-
- node = EnterpriseServer.get_node(name)
- url = EnterpriseServer.url(name)
- token = EnterpriseServer.token(name)
-
- id = :erpc.call(node, Enterprise.Integration, :fetch_env!, ["ENTERPRISE_ID"])
- hub_id = "enterprise-#{id}"
-
- Livebook.Hubs.subscribe([:connection, :secrets])
- Livebook.Hubs.delete_hub(hub_id)
-
- enterprise =
- insert_hub(:enterprise,
- id: hub_id,
- external_id: id,
- url: url,
- token: token
- )
-
- {:ok, session} = Sessions.create_session(notebook: Livebook.Notebook.new())
- Session.set_notebook_hub(session.pid, hub_id)
-
- on_exit(fn ->
- Livebook.Hubs.delete_hub(hub_id)
- Session.close(session.pid)
- stop_new_instance(name)
- end)
-
- {:ok, enterprise: enterprise, session: session, node: node}
- end
-
- test "creates a secret on Enterprise hub",
- %{conn: conn, session: session, enterprise: enterprise} do
- id = enterprise.id
-
- secret =
- build(:secret, name: "BIG_IMPORTANT_SECRET", value: "123", hub_id: id, readonly: true)
-
- {:ok, view, _html} = live(conn, ~p"/sessions/#{session.id}/secrets")
-
- attrs = %{
- secret: %{
- name: secret.name,
- value: secret.value,
- hub_id: enterprise.id
- }
- }
-
- form = element(view, ~s{form[phx-submit="save"]})
- render_change(form, attrs)
- render_submit(form, attrs)
-
- assert_receive {:secret_created, ^secret}
- assert has_element?(view, "#hub-#{enterprise.id}-secret-#{secret.name}")
- end
-
- test "toggle a secret from Enterprise hub",
- %{conn: conn, session: session, enterprise: enterprise, node: node} do
- secret =
- build(:secret,
- name: "POSTGRES_PASSWORD",
- value: "postgres",
- hub_id: enterprise.id,
- readonly: true
- )
-
- {:ok, view, _html} = live(conn, ~p"/sessions/#{session.id}")
-
- :erpc.call(node, Enterprise.Integration, :create_secret, [secret.name, secret.value])
- assert_receive {:secret_created, ^secret}
-
- Session.set_secret(session.pid, secret)
- assert_session_secret(view, session.pid, secret)
- end
-
- test "adding a missing secret using 'Add secret' button",
- %{conn: conn, session: session, enterprise: enterprise} do
- secret =
- build(:secret,
- name: "PGPASS",
- value: "postgres",
- hub_id: enterprise.id,
- readonly: true
- )
-
- # Subscribe and executes the code to trigger
- # the `System.EnvError` exception and outputs the 'Add secret' button
- Session.subscribe(session.id)
- section_id = insert_section(session.pid)
- code = ~s{System.fetch_env!("LB_#{secret.name}")}
- cell_id = insert_text_cell(session.pid, section_id, :code, code)
-
- Session.queue_cell_evaluation(session.pid, cell_id)
- assert_receive {:operation, {:add_cell_evaluation_response, _, ^cell_id, _, _}}
-
- # Enters the session to check if the button exists
- {:ok, view, _} = live(conn, ~p"/sessions/#{session.id}")
- expected_url = ~p"/sessions/#{session.id}/secrets?secret_name=#{secret.name}"
- add_secret_button = element(view, "a[href='#{expected_url}']")
- assert has_element?(add_secret_button)
-
- # Clicks the button and fills the form to create a new secret
- # that prefilled the name with the received from exception.
- render_click(add_secret_button)
- secrets_component = with_target(view, "#secrets-modal")
- form_element = element(secrets_component, "form[phx-submit='save']")
- assert has_element?(form_element)
- attrs = %{value: secret.value, hub_id: enterprise.id}
- render_submit(form_element, %{secret: attrs})
-
- # Checks we received the secret created event from Enterprise
- assert_receive {:secret_created, ^secret}
-
- # Checks if the secret is persisted
- assert secret in Livebook.Hubs.get_secrets()
-
- # Checks if the secret exists and is inside the session,
- # then executes the code cell again and checks if the
- # secret value is what we expected.
- assert_session_secret(view, session.pid, secret)
- Session.queue_cell_evaluation(session.pid, cell_id)
-
- assert_receive {:operation,
- {:add_cell_evaluation_response, _, ^cell_id, {:text, output}, _}}
-
- assert output == "\e[32m\"#{secret.value}\"\e[0m"
- end
-
- test "granting access for missing secret using 'Add secret' button",
- %{conn: conn, session: session, enterprise: enterprise, node: node} do
- secret =
- build(:secret,
- name: "MYSQL_PASS",
- value: "admin",
- hub_id: enterprise.id,
- readonly: true
- )
-
- # Subscribe and executes the code to trigger
- # the `System.EnvError` exception and outputs the 'Add secret' button
- Session.subscribe(session.id)
- section_id = insert_section(session.pid)
- code = ~s{System.fetch_env!("LB_#{secret.name}")}
- cell_id = insert_text_cell(session.pid, section_id, :code, code)
-
- Session.queue_cell_evaluation(session.pid, cell_id)
- assert_receive {:operation, {:add_cell_evaluation_response, _, ^cell_id, _, _}}
-
- # Enters the session to check if the button exists
- {:ok, view, _} = live(conn, ~p"/sessions/#{session.id}")
- expected_url = ~p"/sessions/#{session.id}/secrets?secret_name=#{secret.name}"
- add_secret_button = element(view, "a[href='#{expected_url}']")
- assert has_element?(add_secret_button)
-
- # Persist the secret from the Enterprise
- :erpc.call(node, Enterprise.Integration, :create_secret, [secret.name, secret.value])
-
- # Grant we receive the event, even with eventually delay
- assert_receive {:secret_created, ^secret}, 10_000
-
- # Checks if the secret is persisted
- assert secret in Livebook.Hubs.get_secrets()
-
- # Clicks the button and checks if the 'Grant access' banner
- # is being shown, so clicks it's button to set the app secret
- # to the session, allowing the user to fetches the secret.
- render_click(add_secret_button)
- secrets_component = with_target(view, "#secrets-modal")
-
- assert render(secrets_component) =~
- "in #{hub_label(enterprise)}. Allow this session to access it?"
-
- grant_access_button = element(secrets_component, "button", "Grant access")
- render_click(grant_access_button)
-
- # Checks if the secret exists and is inside the session,
- # then executes the code cell again and checks if the
- # secret value is what we expected.
- assert_session_secret(view, session.pid, secret)
- Session.queue_cell_evaluation(session.pid, cell_id)
-
- assert_receive {:operation,
- {:add_cell_evaluation_response, _, ^cell_id, {:text, output}, _}}
-
- assert output == "\e[32m\"#{secret.value}\"\e[0m"
- end
- end
-end
diff --git a/test/livebook_web/live/session_live_test.exs b/test/livebook_web/live/session_live_test.exs
index 945a99cc6..8640a9ae5 100644
--- a/test/livebook_web/live/session_live_test.exs
+++ b/test/livebook_web/live/session_live_test.exs
@@ -1479,7 +1479,7 @@ defmodule LivebookWeb.SessionLiveTest do
describe "hubs" do
test "selects the notebook hub", %{conn: conn, session: session} do
- hub = insert_hub(:fly)
+ hub = insert_hub(:team)
id = hub.id
personal_id = Livebook.Hubs.Personal.id()
diff --git a/test/support/enterprise_integration_case.ex b/test/support/enterprise_integration_case.ex
deleted file mode 100644
index 2d80e6fcb..000000000
--- a/test/support/enterprise_integration_case.ex
+++ /dev/null
@@ -1,50 +0,0 @@
-defmodule Livebook.EnterpriseIntegrationCase do
- use ExUnit.CaseTemplate
-
- alias Livebook.EnterpriseServer
-
- using do
- quote do
- use LivebookWeb.ConnCase
-
- @moduletag :enterprise_integration
-
- import Livebook.EnterpriseIntegrationCase,
- only: [start_new_instance: 1, stop_new_instance: 1]
-
- alias Livebook.EnterpriseServer
- end
- end
-
- setup_all do
- case EnterpriseServer.start() do
- {:ok, _} -> :ok
- {:error, {:already_started, _}} -> :ok
- end
-
- {:ok,
- url: EnterpriseServer.url(),
- token: EnterpriseServer.token(),
- user: EnterpriseServer.user(),
- node: EnterpriseServer.get_node()}
- end
-
- def start_new_instance(name) do
- suffix = Ecto.UUID.generate() |> :erlang.phash2() |> to_string()
- app_port = Enum.random(1000..9000) |> to_string()
-
- {:ok, _} =
- EnterpriseServer.start(name,
- env: %{
- "DATABASE_URL" =>
- "postgres://postgres:postgres@localhost:5432/enterprise_integration_#{suffix}"
- },
- app_port: app_port
- )
- end
-
- def stop_new_instance(name) do
- EnterpriseServer.disconnect(name)
- EnterpriseServer.drop_database(name)
- end
-end
diff --git a/test/support/factory.ex b/test/support/factory.ex
index 8e743f6c8..91169150b 100644
--- a/test/support/factory.ex
+++ b/test/support/factory.ex
@@ -9,38 +9,21 @@ defmodule Livebook.Factory do
}
end
- def build(:fly_metadata) do
- :fly |> build() |> Livebook.Hubs.Provider.to_metadata()
+ def build(:team_metadata) do
+ :team |> build() |> Livebook.Hubs.Provider.to_metadata()
end
- def build(:fly) do
- %Livebook.Hubs.Fly{
- id: "fly-foo-bar-baz",
- hub_name: "My Personal Hub",
- hub_emoji: "🚀",
- access_token: Livebook.Utils.random_cookie(),
- organization_id: Livebook.Utils.random_id(),
- organization_type: "PERSONAL",
- organization_name: "Foo",
- application_id: "foo-bar-baz"
- }
- end
+ def build(:team) do
+ org = build(:org)
- def build(:enterprise_metadata) do
- :enterprise |> build() |> Livebook.Hubs.Provider.to_metadata()
- end
-
- def build(:enterprise) do
- name = "Enteprise #{Livebook.Utils.random_short_id()}"
-
- %Livebook.Hubs.Enterprise{
- id: "enterprise-#{name}",
- hub_name: name,
+ %Livebook.Hubs.Team{
+ id: "team-#{org.name}",
+ hub_name: org.name,
hub_emoji: "🏭",
org_id: 1,
user_id: 1,
org_key_id: 1,
- teams_key: Livebook.Utils.random_id(),
+ teams_key: org.teams_key,
session_token: Livebook.Utils.random_cookie()
}
end
diff --git a/test/support/integration/enterprise_server.ex b/test/support/integration/enterprise_server.ex
deleted file mode 100644
index b0a1d72e7..000000000
--- a/test/support/integration/enterprise_server.ex
+++ /dev/null
@@ -1,307 +0,0 @@
-defmodule Livebook.EnterpriseServer do
- @moduledoc false
- use GenServer
-
- defstruct [:token, :user, :node, :port, :app_port, :url, :env]
-
- @name __MODULE__
- @timeout 10_000
- @default_enterprise_dir "../enterprise"
-
- def available?() do
- System.get_env("ENTERPRISE_PATH") != nil or File.exists?(@default_enterprise_dir)
- end
-
- def start(name \\ @name, opts \\ []) do
- GenServer.start(__MODULE__, opts, name: name)
- end
-
- def url(name \\ @name) do
- GenServer.call(name, :fetch_url, @timeout)
- end
-
- def token(name \\ @name) do
- GenServer.call(name, :fetch_token, @timeout)
- end
-
- def user(name \\ @name) do
- GenServer.call(name, :fetch_user, @timeout)
- end
-
- def get_node(name \\ @name) do
- GenServer.call(name, :fetch_node, @timeout)
- end
-
- def drop_database(name \\ @name) do
- app_port = GenServer.call(name, :fetch_port)
- state_env = GenServer.call(name, :fetch_env)
-
- app_port |> env(state_env) |> mix(["ecto.drop", "--quiet"])
- end
-
- def reconnect(name \\ @name) do
- GenServer.cast(name, :reconnect)
- end
-
- def disconnect(name \\ @name) do
- GenServer.cast(name, :disconnect)
- end
-
- # GenServer Callbacks
-
- @impl true
- def init(opts) do
- state = struct!(__MODULE__, opts)
-
- {:ok, %{state | node: enterprise_node()}, {:continue, :start_enterprise}}
- end
-
- @impl true
- def handle_continue(:start_enterprise, state) do
- ensure_app_dir!()
- prepare_database(state)
-
- {:noreply, %{state | port: start_enterprise(state)}}
- end
-
- @impl true
- def handle_call(:fetch_token, _from, state) do
- state = if state.token, do: state, else: create_enterprise_token(state)
-
- {:reply, state.token, state}
- end
-
- @impl true
- def handle_call(:fetch_user, _from, state) do
- state = if state.user, do: state, else: create_enterprise_user(state)
-
- {:reply, state.user, state}
- end
-
- @impl true
- def handle_call(:fetch_url, _from, state) do
- state = if state.app_port, do: state, else: %{state | app_port: app_port()}
- url = state.url || fetch_url(state)
-
- {:reply, url, %{state | url: url}}
- end
-
- def handle_call(:fetch_node, _from, state) do
- {:reply, state.node, state}
- end
-
- def handle_call(:fetch_port, _from, state) do
- port = state.app_port || app_port()
- {:reply, port, state}
- end
-
- def handle_call(:fetch_env, _from, state) do
- {:reply, state.env, state}
- end
-
- @impl true
- def handle_cast(:reconnect, state) do
- if state.port do
- {:noreply, state}
- else
- {:noreply, %{state | port: start_enterprise(state)}}
- end
- end
-
- def handle_cast(:disconnect, state) do
- if state.port do
- Port.close(state.port)
- end
-
- {:noreply, %{state | port: nil}}
- end
-
- # Port Callbacks
-
- @impl true
- def handle_info({_port, {:data, message}}, state) do
- info(message)
- {:noreply, state}
- end
-
- def handle_info({_port, {:exit_status, status}}, _state) do
- error("enterprise quit with status #{status}")
- System.halt(status)
- end
-
- # Private
-
- defp create_enterprise_token(state) do
- if user = state.user do
- token = call_erpc_function(state.node, :generate_user_session_token!, [user])
- %{state | token: token}
- else
- user = call_erpc_function(state.node, :create_user)
- token = call_erpc_function(state.node, :generate_user_session_token!, [user])
-
- %{state | user: user, token: token}
- end
- end
-
- defp create_enterprise_user(state) do
- %{state | user: call_erpc_function(state.node, :create_user)}
- end
-
- defp call_erpc_function(node, function, args \\ []) do
- :erpc.call(node, Enterprise.Integration, function, args)
- end
-
- defp start_enterprise(state) do
- env =
- for {key, value} <- env(state), into: [] do
- {String.to_charlist(key), String.to_charlist(value)}
- end
-
- args = [
- "-e",
- "spawn(fn -> IO.gets([]) && System.halt(0) end)",
- "--sname",
- to_string(state.node),
- "--cookie",
- to_string(Node.get_cookie()),
- "-S",
- "mix",
- "phx.server"
- ]
-
- port =
- Port.open({:spawn_executable, elixir_executable()}, [
- :exit_status,
- :use_stdio,
- :stderr_to_stdout,
- :binary,
- :hide,
- env: env,
- cd: app_dir(),
- args: args
- ])
-
- wait_on_start(state, port)
- end
-
- defp fetch_url(state) do
- port = state.app_port || app_port()
- "http://localhost:#{port}"
- end
-
- defp prepare_database(state) do
- :ok = mix(state, ["ecto.drop", "--quiet"])
- :ok = mix(state, ["ecto.create", "--quiet"])
- :ok = mix(state, ["ecto.migrate", "--quiet"])
- end
-
- defp ensure_app_dir! do
- dir = app_dir()
-
- unless File.exists?(dir) do
- IO.puts(
- "Unable to find #{dir}, make sure to clone the enterprise repository " <>
- "into it to run integration tests or set ENTERPRISE_PATH to its location"
- )
-
- System.halt(1)
- end
- end
-
- defp app_dir do
- System.get_env("ENTERPRISE_PATH", @default_enterprise_dir)
- end
-
- defp app_port do
- System.get_env("ENTERPRISE_PORT", "4043")
- end
-
- defp debug do
- System.get_env("ENTERPRISE_DEBUG", "false")
- end
-
- defp proto do
- System.get_env("ENTERPRISE_LIVEBOOK_PROTO_PATH")
- end
-
- defp wait_on_start(state, port) do
- url = state.url || fetch_url(state)
-
- case :httpc.request(:get, {~c"#{url}/public/health", []}, [], []) do
- {:ok, _} ->
- port
-
- {:error, _} ->
- Process.sleep(10)
- wait_on_start(state, port)
- end
- end
-
- defp mix(state, args) when is_struct(state) do
- state |> env() |> mix(args)
- end
-
- defp mix(env, args) do
- cmd_opts = [
- stderr_to_stdout: true,
- env: env,
- cd: app_dir(),
- into: IO.stream(:stdio, :line)
- ]
-
- args = ["--erl", "-elixir ansi_enabled true", "-S", "mix" | args]
-
- case System.cmd(elixir_executable(), args, cmd_opts) do
- {_, 0} -> :ok
- _ -> :error
- end
- end
-
- defp env(state) do
- app_port = state.app_port || app_port()
- env(app_port, state.env)
- end
-
- defp env(app_port, state_env) do
- env = %{
- "MIX_ENV" => "livebook",
- "PORT" => to_string(app_port),
- "DEBUG" => debug()
- }
-
- env = if proto(), do: Map.merge(env, %{"LIVEBOOK_PROTO_PATH" => proto()}), else: env
-
- if state_env do
- Map.merge(env, state_env)
- else
- env
- end
- end
-
- defp elixir_executable do
- System.find_executable("elixir")
- end
-
- defp enterprise_node do
- :"enterprise_#{Livebook.Utils.random_short_id()}@#{hostname()}"
- end
-
- defp hostname do
- [nodename, hostname] =
- node()
- |> Atom.to_charlist()
- |> :string.split(~c"@")
-
- with {:ok, nodenames} <- :erl_epmd.names(hostname),
- true <- List.keymember?(nodenames, nodename, 0) do
- hostname
- else
- _ ->
- raise "Error"
- end
- end
-
- defp info(message), do: log([:blue, message <> "\n"])
- defp error(message), do: log([:red, message <> "\n"])
- defp log(data), do: data |> IO.ANSI.format() |> IO.write()
-end
diff --git a/test/test_helper.exs b/test/test_helper.exs
index bfeff7e8e..da3f691b9 100644
--- a/test/test_helper.exs
+++ b/test/test_helper.exs
@@ -55,7 +55,6 @@ ExUnit.start(
assert_receive_timeout: if(windows?, do: 2_500, else: 1_500),
exclude: [
erl_docs: erl_docs_available?,
- enterprise_integration: not Livebook.EnterpriseServer.available?(),
teams_integration: not Livebook.TeamsServer.available?()
]
)