Livebook Enterprise is currently in closed beta. If you want to learn more,
card_item_bg_color(@id, @selected)}
- phx-click={JS.push("select_provider", value: %{value: @id})}
+ phx-click={JS.push("select_type", value: %{value: @id})}
>
<%= render_slot(@logo) %>
@@ -126,30 +111,7 @@ defmodule LivebookWeb.HubLive do
defp card_item_bg_color(_id, _selected), do: ""
@impl true
- def handle_params(%{"id" => "local-host"}, _url, socket) do
- {:noreply,
- socket |> redirect(to: "/") |> put_flash(:warning, "You can't edit the localhost Hub")}
- end
-
- def handle_params(%{"id" => id}, _url, socket) do
- hub = Hubs.fetch_hub!(id)
- provider = Provider.type(hub)
-
- {:noreply,
- assign(socket,
- operation: :edit,
- hub: hub,
- selected_provider: provider,
- current_page: Routes.hub_path(socket, :edit, hub.id)
- )}
- end
-
- def handle_params(_params, _url, socket) do
- {:noreply, assign(socket, operation: :new, current_page: Routes.hub_path(socket, :new))}
- end
-
- @impl true
- def handle_event("select_provider", %{"value" => service}, socket) do
- {:noreply, assign(socket, selected_provider: service)}
+ def handle_event("select_type", %{"value" => service}, socket) do
+ {:noreply, assign(socket, selected_type: service)}
end
end
diff --git a/lib/livebook_web/router.ex b/lib/livebook_web/router.ex
index 73d63aa85..0ddd0ff9e 100644
--- a/lib/livebook_web/router.ex
+++ b/lib/livebook_web/router.ex
@@ -55,8 +55,8 @@ defmodule LivebookWeb.Router do
live "/explore", ExploreLive, :page
live "/explore/notebooks/:slug", ExploreLive, :notebook
- live "/hub", HubLive, :new
- live "/hub/:id", HubLive, :edit
+ live "/hub", Hub.NewLive, :new, as: :hub
+ live "/hub/:id", Hub.EditLive, :edit, as: :hub
live "/sessions/:id", SessionLive, :page
live "/sessions/:id/shortcuts", SessionLive, :shortcuts
diff --git a/test/livebook/hubs/fly_client_test.exs b/test/livebook/hubs/fly_client_test.exs
index 78c395bac..c59134060 100644
--- a/test/livebook/hubs/fly_client_test.exs
+++ b/test/livebook/hubs/fly_client_test.exs
@@ -1,5 +1,5 @@
defmodule Livebook.Hubs.FlyClientTest do
- use ExUnit.Case
+ use Livebook.DataCase
alias Livebook.Hubs.{Fly, FlyClient}
@@ -68,4 +68,42 @@ defmodule Livebook.Hubs.FlyClientTest do
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"
+ }
+
+ 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
end
diff --git a/test/livebook_web/live/hub/edit_live_test.exs b/test/livebook_web/live/hub/edit_live_test.exs
new file mode 100644
index 000000000..1c09968fd
--- /dev/null
+++ b/test/livebook_web/live/hub/edit_live_test.exs
@@ -0,0 +1,104 @@
+defmodule LivebookWeb.Hub.EditLiveTest do
+ use LivebookWeb.ConnCase
+
+ import Phoenix.LiveViewTest
+
+ alias Livebook.Hubs
+
+ setup do
+ on_exit(&Hubs.clean_hubs/0)
+ :ok
+ end
+
+ describe "fly" do
+ test "updates fly", %{conn: conn} do
+ hub = insert_hub(:fly, id: "fly-987654321", application_id: "987654321")
+ fly_bypass(hub.application_id)
+
+ {:ok, view, html} = live(conn, Routes.hub_path(conn, :edit, hub.id))
+
+ assert html =~ "See app on Fly"
+ assert html =~ "https://#{hub.application_id}.fly.dev"
+
+ attrs = %{
+ "hub_name" => "Personal Hub",
+ "hub_color" => "#FF00FF"
+ }
+
+ view
+ |> element("#fly-form")
+ |> render_change(%{"fly" => attrs})
+
+ refute view
+ |> element("#fly-form .invalid-feedback")
+ |> has_element?()
+
+ assert {:ok, view, _html} =
+ view
+ |> element("#fly-form")
+ |> render_submit(%{"fly" => attrs})
+ |> follow_redirect(conn)
+
+ assert render(view) =~ "Hub updated successfully"
+
+ assert view
+ |> element("#hubs")
+ |> render() =~ ~s/style="color: #FF00FF"/
+
+ assert view
+ |> element("#hubs")
+ |> render() =~ "/hub/fly-987654321"
+
+ assert view
+ |> element("#hubs")
+ |> render() =~ "Personal Hub"
+
+ refute Hubs.fetch_hub!(hub.id) == hub
+ end
+ end
+
+ defp fly_bypass(app_id) do
+ bypass = Bypass.open()
+ Application.put_env(:livebook, :fly_graphql_endpoint, "http://localhost:#{bypass.port}")
+
+ Bypass.expect(bypass, "POST", "/", fn conn ->
+ {:ok, body, conn} = Plug.Conn.read_body(conn)
+
+ response =
+ case Jason.decode!(body) do
+ %{"variables" => %{"appId" => ^app_id}} -> fetch_app_response(app_id)
+ %{"variables" => %{}} -> fetch_apps_response(app_id)
+ end
+
+ conn
+ |> Plug.Conn.put_resp_content_type("application/json")
+ |> Plug.Conn.resp(200, Jason.encode!(response))
+ end)
+ end
+
+ defp fetch_apps_response(app_id) do
+ app = %{
+ "id" => app_id,
+ "organization" => %{
+ "id" => "l3soyvjmvtmwtl6l2drnbfuvltipprge",
+ "name" => "Foo Bar",
+ "type" => "PERSONAL"
+ }
+ }
+
+ %{"data" => %{"apps" => %{"nodes" => [app]}}}
+ end
+
+ defp fetch_app_response(app_id) do
+ app = %{
+ "id" => app_id,
+ "name" => app_id,
+ "hostname" => app_id <> ".fly.dev",
+ "platformVersion" => "nomad",
+ "deployed" => true,
+ "status" => "running"
+ }
+
+ %{"data" => %{"app" => app}}
+ end
+end
diff --git a/test/livebook_web/live/hub_live_test.exs b/test/livebook_web/live/hub/new_live_test.exs
similarity index 60%
rename from test/livebook_web/live/hub_live_test.exs
rename to test/livebook_web/live/hub/new_live_test.exs
index 111400b77..27beb9e9b 100644
--- a/test/livebook_web/live/hub_live_test.exs
+++ b/test/livebook_web/live/hub/new_live_test.exs
@@ -1,5 +1,5 @@
-defmodule LivebookWeb.HubLiveTest do
- use LivebookWeb.ConnCase, async: true
+defmodule LivebookWeb.Hub.NewLiveTest do
+ use LivebookWeb.ConnCase
import Phoenix.LiveViewTest
@@ -7,12 +7,11 @@ defmodule LivebookWeb.HubLiveTest do
setup do
on_exit(&Hubs.clean_hubs/0)
-
:ok
end
test "render hub selection cards", %{conn: conn} do
- {:ok, _view, html} = live(conn, "/hub")
+ {:ok, _view, html} = live(conn, Routes.hub_path(conn, :new))
assert html =~ "Fly"
assert html =~ "Livebook Enterprise"
@@ -20,9 +19,9 @@ defmodule LivebookWeb.HubLiveTest do
describe "fly" do
test "persists fly", %{conn: conn} do
- fly_app_bypass("123456789")
+ fly_bypass("123456789")
- {:ok, view, _html} = live(conn, "/hub")
+ {:ok, view, _html} = live(conn, Routes.hub_path(conn, :new))
assert view
|> element("#fly")
@@ -54,7 +53,7 @@ defmodule LivebookWeb.HubLiveTest do
|> render_submit(%{"fly" => attrs})
|> follow_redirect(conn)
- assert render(view) =~ "Hub created successfully"
+ assert render(view) =~ "Hub added successfully"
assert view
|> element("#hubs")
@@ -69,60 +68,11 @@ defmodule LivebookWeb.HubLiveTest do
|> render() =~ "My Foo Hub"
end
- test "updates fly", %{conn: conn} do
- fly_app_bypass("987654321")
- fly = insert_hub(:fly, id: "fly-987654321", application_id: "987654321")
-
- {:ok, view, _html} = live(conn, "/hub/fly-987654321")
-
- assert render(view) =~ "2. Configure your Hub"
-
- assert render(view) =~
- ~s()
-
- attrs = %{
- "access_token" => "dummy access token",
- "application_id" => "987654321",
- "hub_name" => "Personal Hub",
- "hub_color" => "#FF00FF"
- }
-
- view
- |> element("#fly-form")
- |> render_change(%{"fly" => attrs})
-
- refute view
- |> element("#fly-form .invalid-feedback")
- |> has_element?()
-
- assert {:ok, view, _html} =
- view
- |> element("#fly-form")
- |> render_submit(%{"fly" => attrs})
- |> follow_redirect(conn)
-
- assert render(view) =~ "Hub updated successfully"
-
- assert view
- |> element("#hubs")
- |> render() =~ ~s/style="color: #FF00FF"/
-
- assert view
- |> element("#hubs")
- |> render() =~ "/hub/fly-987654321"
-
- assert view
- |> element("#hubs")
- |> render() =~ "Personal Hub"
-
- refute Hubs.fetch_hub!("fly-987654321") == fly
- end
-
test "fails to create existing hub", %{conn: conn} do
- fly = insert_hub(:fly, id: "fly-foo", application_id: "foo")
- fly_app_bypass("foo")
+ hub = insert_hub(:fly, id: "fly-foo", application_id: "foo")
+ fly_bypass(hub.application_id)
- {:ok, view, _html} = live(conn, "/hub")
+ {:ok, view, _html} = live(conn, Routes.hub_path(conn, :new))
assert view
|> element("#fly")
@@ -154,24 +104,40 @@ defmodule LivebookWeb.HubLiveTest do
assert view
|> element("#hubs")
- |> render() =~ ~s/style="color: #{fly.hub_color}"/
+ |> render() =~ ~s/style="color: #{hub.hub_color}"/
assert view
|> element("#hubs")
- |> render() =~ "/hub/fly-foo"
+ |> render() =~ Routes.hub_path(conn, :edit, hub.id)
assert view
|> element("#hubs")
- |> render() =~ fly.hub_name
+ |> render() =~ hub.hub_name
- assert Hubs.fetch_hub!("fly-foo") == fly
+ assert Hubs.fetch_hub!(hub.id) == hub
end
end
- defp fly_app_bypass(app_id) do
+ defp fly_bypass(app_id) do
bypass = Bypass.open()
Application.put_env(:livebook, :fly_graphql_endpoint, "http://localhost:#{bypass.port}")
+ Bypass.expect(bypass, "POST", "/", fn conn ->
+ {:ok, body, conn} = Plug.Conn.read_body(conn)
+
+ response =
+ case Jason.decode!(body) do
+ %{"variables" => %{"appId" => ^app_id}} -> fetch_app_response(app_id)
+ %{"variables" => %{}} -> fetch_apps_response(app_id)
+ end
+
+ conn
+ |> Plug.Conn.put_resp_content_type("application/json")
+ |> Plug.Conn.resp(200, Jason.encode!(response))
+ end)
+ end
+
+ defp fetch_apps_response(app_id) do
app = %{
"id" => app_id,
"organization" => %{
@@ -181,12 +147,19 @@ defmodule LivebookWeb.HubLiveTest do
}
}
- response = %{"data" => %{"apps" => %{"nodes" => [app]}}}
+ %{"data" => %{"apps" => %{"nodes" => [app]}}}
+ end
- Bypass.expect(bypass, "POST", "/", fn conn ->
- conn
- |> Plug.Conn.put_resp_content_type("application/json")
- |> Plug.Conn.resp(200, Jason.encode!(response))
- end)
+ defp fetch_app_response(app_id) do
+ app = %{
+ "id" => app_id,
+ "name" => app_id,
+ "hostname" => app_id <> ".fly.dev",
+ "platformVersion" => "nomad",
+ "deployed" => true,
+ "status" => "running"
+ }
+
+ %{"data" => %{"app" => app}}
end
end