livebook/test/livebook_teams/hubs_test.exs
2025-05-27 08:54:21 -03:00

220 lines
7.6 KiB
Elixir

defmodule Livebook.HubsTest do
use Livebook.TeamsIntegrationCase, async: true
alias Livebook.Hubs
@moduletag teams_for: :user
setup :teams
@moduletag subscribe_to_hubs_topics: [:connection, :file_systems, :secrets]
@moduletag subscribe_to_teams_topics: [:clients]
test "get_hubs/0 returns a list of persisted hubs", %{team: team} do
assert team in Hubs.get_hubs()
assert Hubs.hub_exists?(team.id)
end
test "get_metadata/0 returns a list of persisted hubs normalized", %{team: team} do
assert %{provider: ^team} = metadata = Hubs.Provider.to_metadata(team)
assert metadata in Hubs.get_metadata()
end
@tag teams_persisted: false
test "fetch_hub!/1 returns one persisted team", %{team: team} do
assert_raise Livebook.Storage.NotFoundError,
~s/could not find entry in "hubs" with ID "#{team.id}"/,
fn ->
Hubs.fetch_hub!(team.id)
end
Hubs.save_hub(team)
assert Hubs.fetch_hub!(team.id) == team
end
describe "save_hub/1" do
@tag teams_persisted: false
test "persists hub", %{team: team} do
refute Hubs.hub_exists?(team.id)
Hubs.save_hub(team)
assert Hubs.fetch_hub!(team.id) == team
end
test "updates hub", %{team: team} do
Hubs.save_hub(%{team | hub_emoji: "🐈"})
assert Hubs.fetch_hub!(team.id).hub_emoji == "🐈"
end
end
describe "create_secret/2" do
test "creates a new secret", %{team: team} do
name = secret_name(team)
value = team.id
secret = build(:secret, name: name, value: value, hub_id: team.id)
assert :ok = Hubs.create_secret(team, secret)
assert secret in Hubs.get_secrets(team)
# Guarantee uniqueness
assert {:error, errors} = Hubs.create_secret(team, secret)
assert "has already been taken" in errors[:name]
end
test "returns changeset errors when data is invalid", %{team: team} do
secret = build(:secret, name: "LB_FOO", value: "BAR", hub_id: team.id)
assert {:error, errors} = Hubs.create_secret(team, secret)
assert "cannot start with the LB_ prefix" in errors[:name]
end
end
describe "update_secret/2" do
test "updates a secret", %{team: team} do
name = secret_name(team)
value = team.id
secret = build(:secret, name: name, value: value, hub_id: team.id)
assert Hubs.create_secret(team, secret) == :ok
assert_receive {:secret_created, %{name: ^name, value: ^value, hub_id: ^value}}
assert secret in Hubs.get_secrets(team)
new_value = "BAZ"
updated_secret = Map.replace!(secret, :value, new_value)
assert Hubs.update_secret(team, updated_secret) == :ok
assert_receive {:secret_updated, %{name: ^name, value: ^new_value, hub_id: ^value}}
refute secret in Hubs.get_secrets(team)
assert updated_secret in Hubs.get_secrets(team)
end
test "returns changeset errors when data is invalid", %{team: team} do
name = secret_name(team)
value = team.id
secret = build(:secret, name: name, value: value, hub_id: team.id)
assert Hubs.create_secret(team, secret) == :ok
assert_receive {:secret_created, %{name: ^name, value: ^value}}
updated_secret = Map.replace!(secret, :value, "")
assert {:error, errors} = Hubs.update_secret(team, updated_secret)
assert "can't be blank" in errors[:value]
end
end
test "delete_secret/2 deletes a secret", %{team: team} do
name = secret_name(team)
value = team.id
secret = build(:secret, name: name, value: value, hub_id: team.id)
assert Hubs.create_secret(team, secret) == :ok
assert_receive {:secret_created, %{name: ^name, value: ^value, hub_id: ^value}}
assert secret in Hubs.get_secrets(team)
assert Hubs.delete_secret(team, secret) == :ok
assert_receive {:secret_deleted, %{name: ^name, value: ^value, hub_id: ^value}}
refute secret in Hubs.get_secrets(team)
# Guarantee it's been removed and will return HTTP status 404
assert Hubs.delete_secret(team, secret) ==
{:transport_error,
"Something went wrong, try again later or please file a bug if it persists"}
end
describe "create_file_system/2" do
test "creates a new file system", %{team: team} do
bucket_url = "https://#{team.id}.s3.amazonaws.com"
file_system = build(:fs_s3, bucket_url: bucket_url)
region = file_system.region
assert Hubs.create_file_system(team, file_system) == :ok
assert_receive {:file_system_created, %{bucket_url: ^bucket_url, region: ^region}}
# Guarantee uniqueness
assert {:error, errors} = Hubs.create_file_system(team, file_system)
assert "has already been taken" in errors[:bucket_url]
end
test "returns changeset errors when data is invalid", %{team: team} do
file_system = build(:fs_s3, bucket_url: nil)
assert {:error, errors} = Hubs.create_file_system(team, file_system)
assert "can't be blank" in errors[:bucket_url]
end
end
describe "update_file_system/2" do
test "updates a file system", %{team: team} do
bucket_url = "https://#{team.id}.s3.amazonaws.com"
file_system = build(:fs_s3, bucket_url: bucket_url)
assert Hubs.create_file_system(team, file_system) == :ok
assert_receive {:file_system_created,
%{bucket_url: ^bucket_url, external_id: external_id} = file_system}
assert file_system in Hubs.get_file_systems(team)
updated_file_system = Map.replace!(file_system, :region, "eu-central-1")
assert Hubs.update_file_system(team, updated_file_system) == :ok
assert_receive {:file_system_updated, %{external_id: ^external_id, region: "eu-central-1"}}
refute file_system in Hubs.get_file_systems(team)
assert updated_file_system in Hubs.get_file_systems(team)
end
test "returns changeset errors when data is invalid",
%{team: team, node: node, org_key: org_key} do
file_system = TeamsRPC.create_file_system(node, team, org_key)
update_file_system = Map.replace!(file_system, :bucket_url, "")
assert {:error, errors} = Hubs.update_file_system(team, update_file_system)
assert "can't be blank" in errors[:bucket_url]
end
end
test "delete_file_system/2 deletes a file system", %{team: team} do
bucket_url = "https://#{team.id}.s3.amazonaws.com"
file_system = build(:fs_s3, bucket_url: bucket_url)
assert Hubs.create_file_system(team, file_system) == :ok
assert_receive {:file_system_created,
%{bucket_url: ^bucket_url, external_id: external_id} = file_system}
assert file_system in Hubs.get_file_systems(team)
assert Hubs.delete_file_system(team, file_system) == :ok
assert_receive {:file_system_deleted, %{external_id: ^external_id}}
refute file_system in Hubs.get_file_systems(team)
# Guarantee it's been removed and will return HTTP status 404
assert Hubs.delete_file_system(team, file_system) ==
{:transport_error,
"Something went wrong, try again later or please file a bug if it persists"}
end
test "generates and verifies stamp for a notebook", %{team: team} do
notebook_source = """
# Team notebook
# Intro
```elixir
IO.puts("Hello!")
```
"""
metadata = %{"key" => "value"}
assert {:ok, stamp} = Hubs.Provider.notebook_stamp(team, notebook_source, metadata)
assert {:ok, ^metadata} = Hubs.Provider.verify_notebook_stamp(team, notebook_source, stamp)
assert {:error, :invalid} =
Hubs.Provider.verify_notebook_stamp(team, notebook_source <> "change\n", stamp)
end
defp secret_name(%{id: id}) do
id
|> String.replace("-", "_")
|> String.upcase()
end
end