mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-11-08 13:11:56 +08:00
Improve integration tests infrastructure (#2583)
This commit is contained in:
parent
fdac5cfe4f
commit
3d289448cd
5 changed files with 218 additions and 497 deletions
|
|
@ -6,168 +6,37 @@ defmodule Livebook.Hubs.TeamClientTest do
|
|||
setup do
|
||||
Livebook.Hubs.Broadcasts.subscribe([:connection, :file_systems, :secrets])
|
||||
Livebook.Teams.Broadcasts.subscribe([:clients, :deployment_groups, :app_deployments, :agents])
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
test "rejects the web socket connection with invalid credentials", %{user: user, token: token} do
|
||||
team =
|
||||
build(:team,
|
||||
user_id: user.id,
|
||||
org_id: 123_456,
|
||||
org_key_id: 123_456,
|
||||
session_token: token
|
||||
)
|
||||
|
||||
id = team.id
|
||||
|
||||
TeamClient.start_link(team)
|
||||
|
||||
assert_receive {:hub_server_error, ^id, error}
|
||||
|
||||
assert error ==
|
||||
"#{team.hub_name}: Your session is out-of-date. Please re-join the organization."
|
||||
|
||||
refute Livebook.Hubs.hub_exists?(team.id)
|
||||
end
|
||||
|
||||
describe "handle events" do
|
||||
setup %{user: user, node: node} do
|
||||
team = create_team_hub(user, node)
|
||||
describe "connect" do
|
||||
test "successfully authenticates the websocket connection", %{user: user, node: node} do
|
||||
team = build_team_hub(user, node)
|
||||
id = team.id
|
||||
TeamClient.start_link(team)
|
||||
|
||||
assert_receive {:hub_connected, ^id}
|
||||
assert_receive {:client_connected, ^id}
|
||||
|
||||
{:ok, team: team}
|
||||
end
|
||||
|
||||
test "receives secret events", %{team: team} do
|
||||
secret = build(:secret, name: "SECRET", value: "BAR")
|
||||
assert Livebook.Hubs.create_secret(team, secret) == :ok
|
||||
|
||||
name = secret.name
|
||||
value = secret.value
|
||||
|
||||
# receives `{:secret_created, secret}` event
|
||||
# with the value decrypted
|
||||
assert_receive {:secret_created, %{name: ^name, value: ^value}}
|
||||
|
||||
# updates the secret
|
||||
updated_secret = Map.replace!(secret, :value, "BAZ")
|
||||
assert Livebook.Hubs.update_secret(team, updated_secret) == :ok
|
||||
|
||||
new_value = updated_secret.value
|
||||
|
||||
# receives `{:secret_updated, secret}` event
|
||||
# with the value decrypted
|
||||
assert_receive {:secret_updated, %{name: ^name, value: ^new_value}}
|
||||
|
||||
# deletes the secret
|
||||
assert Livebook.Hubs.delete_secret(team, updated_secret) == :ok
|
||||
|
||||
# receives `{:secret_deleted, secret}` event
|
||||
assert_receive {:secret_deleted, %{name: ^name, value: ^new_value}}
|
||||
end
|
||||
|
||||
test "receives file system events", %{team: team} do
|
||||
file_system =
|
||||
build(:fs_s3, bucket_url: "https://file_system.s3.amazonaws.com", region: "us-east-1")
|
||||
|
||||
assert Livebook.Hubs.create_file_system(team, file_system) == :ok
|
||||
|
||||
bucket_url = file_system.bucket_url
|
||||
region = file_system.region
|
||||
|
||||
# receives `{:file_system_created, file_system}` event
|
||||
assert_receive {:file_system_created,
|
||||
%{external_id: id, bucket_url: ^bucket_url, region: ^region}}
|
||||
|
||||
# updates the file system
|
||||
updated_file_system = %{file_system | region: "eu-central-1", external_id: id}
|
||||
assert Livebook.Hubs.update_file_system(team, updated_file_system) == :ok
|
||||
|
||||
new_region = updated_file_system.region
|
||||
|
||||
# receives `{:file_system_updated, file_system}` event
|
||||
assert_receive {:file_system_updated,
|
||||
%{external_id: ^id, bucket_url: ^bucket_url, region: ^new_region}}
|
||||
|
||||
# deletes the file system
|
||||
assert Livebook.Hubs.delete_file_system(team, updated_file_system) == :ok
|
||||
|
||||
# receives `{:file_system_deleted, file_system}` event
|
||||
assert_receive {:file_system_deleted, %{external_id: ^id, bucket_url: ^bucket_url}}
|
||||
end
|
||||
|
||||
test "receives deployment group events", %{team: team} do
|
||||
deployment_group =
|
||||
build(:deployment_group, name: "DEPLOYMENT_GROUP_#{team.id}", mode: :online)
|
||||
|
||||
assert {:ok, _} = Livebook.Teams.create_deployment_group(team, deployment_group)
|
||||
%{name: name, mode: mode} = deployment_group
|
||||
|
||||
# receives `{:event, :deployment_group_created, deployment_group}` event
|
||||
assert_receive {:deployment_group_created, %{name: ^name, mode: ^mode}}
|
||||
end
|
||||
|
||||
@tag :tmp_dir
|
||||
test "receives app events", %{team: team, node: node, tmp_dir: tmp_dir} do
|
||||
deployment_group = build(:deployment_group, name: team.id, mode: :online)
|
||||
assert {:ok, id} = Livebook.Teams.create_deployment_group(team, deployment_group)
|
||||
|
||||
id = to_string(id)
|
||||
|
||||
assert_receive {:deployment_group_created, %{id: ^id}}
|
||||
|
||||
# creates the app deployment
|
||||
slug = Livebook.Utils.random_short_id()
|
||||
title = "MyNotebook-#{slug}"
|
||||
app_settings = %{Livebook.Notebook.AppSettings.new() | slug: slug}
|
||||
|
||||
notebook = %{
|
||||
Livebook.Notebook.new()
|
||||
| app_settings: app_settings,
|
||||
name: title,
|
||||
hub_id: team.id,
|
||||
deployment_group_id: id
|
||||
}
|
||||
|
||||
files_dir = Livebook.FileSystem.File.local(tmp_dir)
|
||||
{:ok, app_deployment} = Livebook.Teams.AppDeployment.new(notebook, files_dir)
|
||||
:ok = Livebook.Teams.deploy_app(team, app_deployment)
|
||||
|
||||
sha = app_deployment.sha
|
||||
multi_session = app_settings.multi_session
|
||||
access_type = app_settings.access_type
|
||||
|
||||
assert_receive {:app_deployment_started,
|
||||
%Livebook.Teams.AppDeployment{
|
||||
slug: ^slug,
|
||||
sha: ^sha,
|
||||
title: ^title,
|
||||
multi_session: ^multi_session,
|
||||
access_type: ^access_type,
|
||||
deployment_group_id: ^id
|
||||
} = app_deployment}
|
||||
|
||||
# force app deployment to be deleted
|
||||
erpc_call(node, :toggle_app_deployment, [app_deployment.id, team.org_id])
|
||||
|
||||
assert_receive {:app_deployment_stopped, ^app_deployment}
|
||||
end
|
||||
|
||||
test "receives the user events", %{team: team, node: node} do
|
||||
Livebook.Hubs.Broadcasts.subscribe([:crud])
|
||||
|
||||
# force user to be deleted from org
|
||||
erpc_call(node, :delete_user_org, [team.user_id, team.org_id])
|
||||
test "rejects the web socket connection with invalid credentials", %{user: user, token: token} do
|
||||
team =
|
||||
build(:team,
|
||||
user_id: user.id,
|
||||
org_id: 123_456,
|
||||
org_key_id: 123_456,
|
||||
session_token: token
|
||||
)
|
||||
|
||||
id = team.id
|
||||
reason = "#{team.hub_name}: you were removed from the org"
|
||||
|
||||
assert_receive {:hub_server_error, ^id, ^reason}
|
||||
assert_receive {:hub_deleted, ^id}
|
||||
refute team in Livebook.Hubs.get_hubs()
|
||||
start_supervised!({TeamClient, team})
|
||||
|
||||
assert_receive {:hub_server_error, ^id, error}
|
||||
|
||||
assert error ==
|
||||
"#{team.hub_name}: Your session is out-of-date. Please re-join the organization."
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -187,6 +56,20 @@ defmodule Livebook.Hubs.TeamClientTest do
|
|||
{:ok, team: team, user_connected: user_connected}
|
||||
end
|
||||
|
||||
test "receives the user events", %{team: team, node: node} do
|
||||
Livebook.Hubs.Broadcasts.subscribe([:crud])
|
||||
|
||||
# force user to be deleted from org
|
||||
erpc_call(node, :delete_user_org, [team.user_id, team.org_id])
|
||||
|
||||
id = team.id
|
||||
reason = "#{team.hub_name}: you were removed from the org"
|
||||
|
||||
assert_receive {:hub_server_error, ^id, ^reason}
|
||||
assert_receive {:hub_deleted, ^id}
|
||||
refute team in Livebook.Hubs.get_hubs()
|
||||
end
|
||||
|
||||
test "dispatches the secrets list", %{team: team, user_connected: user_connected} do
|
||||
secret =
|
||||
build(:secret,
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
defmodule Livebook.Hubs.TeamTest do
|
||||
use Livebook.TeamsIntegrationCase, async: true
|
||||
|
||||
alias Livebook.Hubs.Provider
|
||||
|
||||
describe "stamping" do
|
||||
test "generates and verifies stamp for a notebook", %{user: user, node: node} do
|
||||
team = create_team_hub(user, node)
|
||||
|
||||
notebook_source = """
|
||||
# Team notebook
|
||||
|
||||
# Intro
|
||||
|
||||
```elixir
|
||||
IO.puts("Hello!")
|
||||
```
|
||||
"""
|
||||
|
||||
metadata = %{"key" => "value"}
|
||||
|
||||
assert {:ok, stamp} = Provider.notebook_stamp(team, notebook_source, metadata)
|
||||
|
||||
assert {:ok, ^metadata} = Provider.verify_notebook_stamp(team, notebook_source, stamp)
|
||||
|
||||
assert {:error, :invalid} =
|
||||
Provider.verify_notebook_stamp(team, notebook_source <> "change\n", stamp)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -3,8 +3,15 @@ defmodule Livebook.HubsTest do
|
|||
|
||||
alias Livebook.Hubs
|
||||
|
||||
setup do
|
||||
Livebook.Hubs.Broadcasts.subscribe([:connection, :file_systems, :secrets])
|
||||
Livebook.Teams.Broadcasts.subscribe([:clients])
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
test "get_hubs/0 returns a list of persisted hubs", %{user: user, node: node} do
|
||||
team = create_team_hub(user, node)
|
||||
team = connect_to_teams(user, node)
|
||||
assert team in Hubs.get_hubs()
|
||||
|
||||
Hubs.delete_hub(team.id)
|
||||
|
|
@ -12,7 +19,7 @@ defmodule Livebook.HubsTest do
|
|||
end
|
||||
|
||||
test "get_metadata/0 returns a list of persisted hubs normalized", %{user: user, node: node} do
|
||||
team = create_team_hub(user, node)
|
||||
team = connect_to_teams(user, node)
|
||||
metadata = Hubs.Provider.to_metadata(team)
|
||||
|
||||
assert metadata in Hubs.get_metadata()
|
||||
|
|
@ -28,7 +35,7 @@ defmodule Livebook.HubsTest do
|
|||
Hubs.fetch_hub!("nonexistent")
|
||||
end
|
||||
|
||||
team = create_team_hub(user, node)
|
||||
team = connect_to_teams(user, node)
|
||||
|
||||
assert Hubs.fetch_hub!(team.id) == team
|
||||
end
|
||||
|
|
@ -49,7 +56,7 @@ defmodule Livebook.HubsTest do
|
|||
end
|
||||
|
||||
test "updates hub", %{user: user, node: node} do
|
||||
team = create_team_hub(user, node)
|
||||
team = connect_to_teams(user, node)
|
||||
Hubs.save_hub(%{team | hub_emoji: "🐈"})
|
||||
|
||||
assert Hubs.fetch_hub!(team.id).hub_emoji == "🐈"
|
||||
|
|
@ -58,10 +65,13 @@ defmodule Livebook.HubsTest do
|
|||
|
||||
describe "create_secret/2" do
|
||||
test "creates a new secret", %{user: user, node: node} do
|
||||
hub = create_team_hub(user, node)
|
||||
secret = build(:secret, name: "FOO", value: "BAR")
|
||||
hub = connect_to_teams(user, node)
|
||||
name = secret_name(hub)
|
||||
value = hub.id
|
||||
secret = build(:secret, name: name, value: value, hub_id: hub.id)
|
||||
|
||||
assert Hubs.create_secret(hub, secret) == :ok
|
||||
assert secret in Hubs.get_secrets(hub)
|
||||
|
||||
# Guarantee uniqueness
|
||||
assert {:error, changeset} = Hubs.create_secret(hub, secret)
|
||||
|
|
@ -69,69 +79,83 @@ defmodule Livebook.HubsTest do
|
|||
end
|
||||
|
||||
test "returns changeset errors when data is invalid", %{user: user, node: node} do
|
||||
hub = create_team_hub(user, node)
|
||||
secret = build(:secret, name: "LB_FOO", value: "BAR")
|
||||
hub = connect_to_teams(user, node)
|
||||
secret = build(:secret, name: "LB_FOO", value: "BAR", hub_id: hub.id)
|
||||
|
||||
assert {:error, changeset} = Hubs.create_secret(hub, secret)
|
||||
assert "cannot start with the LB_ prefix" in errors_on(changeset).name
|
||||
refute secret in Hubs.get_secrets(hub)
|
||||
end
|
||||
end
|
||||
|
||||
describe "update_secret/2" do
|
||||
test "updates a secret", %{user: user, node: node} do
|
||||
hub = create_team_hub(user, node)
|
||||
secret = build(:secret, name: "UPDATE_ME", value: "BAR")
|
||||
hub = connect_to_teams(user, node)
|
||||
name = secret_name(hub)
|
||||
value = hub.id
|
||||
secret = build(:secret, name: name, value: value, hub_id: hub.id)
|
||||
|
||||
assert Hubs.create_secret(hub, secret) == :ok
|
||||
assert_receive {:secret_created, %{name: ^name, value: ^value}}
|
||||
assert secret in Hubs.get_secrets(hub)
|
||||
|
||||
update_secret = Map.replace!(secret, :value, "BAZ")
|
||||
assert Hubs.update_secret(hub, update_secret) == :ok
|
||||
new_value = "BAZ"
|
||||
updated_secret = Map.replace!(secret, :value, new_value)
|
||||
|
||||
assert Hubs.update_secret(hub, updated_secret) == :ok
|
||||
assert_receive {:secret_updated, %{name: ^name, value: ^new_value}}
|
||||
refute secret in Hubs.get_secrets(hub)
|
||||
assert updated_secret in Hubs.get_secrets(hub)
|
||||
end
|
||||
|
||||
test "returns changeset errors when data is invalid", %{user: user, node: node} do
|
||||
hub = create_team_hub(user, node)
|
||||
secret = build(:secret, name: "FIX_ME", value: "BAR")
|
||||
hub = connect_to_teams(user, node)
|
||||
name = secret_name(hub)
|
||||
value = hub.id
|
||||
secret = build(:secret, name: name, value: value, hub_id: hub.id)
|
||||
|
||||
assert Hubs.create_secret(hub, secret) == :ok
|
||||
assert_receive {:secret_created, %{name: ^name, value: ^value}}
|
||||
|
||||
update_secret = Map.replace!(secret, :value, "")
|
||||
updated_secret = Map.replace!(secret, :value, "")
|
||||
|
||||
assert {:error, changeset} = Hubs.update_secret(hub, update_secret)
|
||||
assert {:error, changeset} = Hubs.update_secret(hub, updated_secret)
|
||||
assert "can't be blank" in errors_on(changeset).value
|
||||
end
|
||||
end
|
||||
|
||||
describe "delete_secret/2" do
|
||||
test "deletes a secret", %{user: user, node: node} do
|
||||
hub = create_team_hub(user, node)
|
||||
secret = build(:secret, name: "DELETE_ME", value: "BAR")
|
||||
test "delete_secret/2 deletes a secret", %{user: user, node: node} do
|
||||
hub = connect_to_teams(user, node)
|
||||
name = secret_name(hub)
|
||||
value = hub.id
|
||||
secret = build(:secret, name: name, value: value, hub_id: hub.id)
|
||||
|
||||
assert Hubs.create_secret(hub, secret) == :ok
|
||||
assert Hubs.delete_secret(hub, secret) == :ok
|
||||
assert Hubs.create_secret(hub, secret) == :ok
|
||||
assert_receive {:secret_created, %{name: ^name, value: ^value}}
|
||||
assert secret in Hubs.get_secrets(hub)
|
||||
|
||||
# Guarantee it's been removed and will return HTTP status 404
|
||||
assert Hubs.delete_secret(hub, secret) ==
|
||||
{:transport_error,
|
||||
"Something went wrong, try again later or please file a bug if it persists"}
|
||||
end
|
||||
assert Hubs.delete_secret(hub, secret) == :ok
|
||||
assert_receive {:secret_deleted, %{name: ^name, value: ^value}}
|
||||
refute secret in Hubs.get_secrets(hub)
|
||||
|
||||
test "returns transport errors when secret doesn't exists", %{user: user, node: node} do
|
||||
hub = create_team_hub(user, node)
|
||||
secret = build(:secret, name: "I_CANT_EXIST", value: "BAR")
|
||||
# Guarantee it's been removed and will return HTTP status 404
|
||||
assert Hubs.delete_secret(hub, secret) ==
|
||||
{:transport_error,
|
||||
"Something went wrong, try again later or please file a bug if it persists"}
|
||||
|
||||
# Guarantee it doesn't exists and will return HTTP status 404
|
||||
assert Hubs.delete_secret(hub, secret) ==
|
||||
{:transport_error,
|
||||
"Something went wrong, try again later or please file a bug if it persists"}
|
||||
end
|
||||
refute_receive {:secret_deleted, _}
|
||||
end
|
||||
|
||||
describe "create_file_system/2" do
|
||||
test "creates a new file system", %{user: user, node: node} do
|
||||
hub = create_team_hub(user, node)
|
||||
file_system = build(:fs_s3, bucket_url: "https://file_system_created.s3.amazonaws.com")
|
||||
hub = connect_to_teams(user, node)
|
||||
|
||||
bucket_url = "https://#{hub.id}.s3.amazonaws.com"
|
||||
file_system = build(:fs_s3, bucket_url: bucket_url)
|
||||
region = file_system.region
|
||||
|
||||
assert Hubs.create_file_system(hub, file_system) == :ok
|
||||
assert_receive {:file_system_created, %{bucket_url: ^bucket_url, region: ^region}}
|
||||
|
||||
# Guarantee uniqueness
|
||||
assert {:error, changeset} = Hubs.create_file_system(hub, file_system)
|
||||
|
|
@ -139,32 +163,35 @@ defmodule Livebook.HubsTest do
|
|||
end
|
||||
|
||||
test "returns changeset errors when data is invalid", %{user: user, node: node} do
|
||||
hub = create_team_hub(user, node)
|
||||
hub = connect_to_teams(user, node)
|
||||
file_system = build(:fs_s3, bucket_url: nil)
|
||||
|
||||
assert {:error, changeset} = Hubs.create_file_system(hub, file_system)
|
||||
assert "can't be blank" in errors_on(changeset).bucket_url
|
||||
refute_receive {:file_system_created, _}
|
||||
end
|
||||
end
|
||||
|
||||
describe "update_file_system/2" do
|
||||
test "updates a file system", %{user: user, node: node} do
|
||||
hub = create_team_hub(user, node)
|
||||
teams_file_system = create_teams_file_system(hub, node)
|
||||
hub = connect_to_teams(user, node)
|
||||
bucket_url = "https://#{hub.id}.s3.amazonaws.com"
|
||||
file_system = build(:fs_s3, bucket_url: bucket_url)
|
||||
|
||||
file_system =
|
||||
build(:fs_s3,
|
||||
bucket_url: teams_file_system.name,
|
||||
region: "us-east-1",
|
||||
external_id: to_string(teams_file_system.id)
|
||||
)
|
||||
assert Hubs.create_file_system(hub, file_system) == :ok
|
||||
assert_receive {:file_system_created, %{external_id: external_id} = file_system}
|
||||
assert file_system in Hubs.get_file_systems(hub)
|
||||
|
||||
update_file_system = Map.replace!(file_system, :region, "eu-central-1")
|
||||
assert Hubs.update_file_system(hub, update_file_system) == :ok
|
||||
updated_file_system = Map.replace!(file_system, :region, "eu-central-1")
|
||||
|
||||
assert Hubs.update_file_system(hub, 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(hub)
|
||||
assert updated_file_system in Hubs.get_file_systems(hub)
|
||||
end
|
||||
|
||||
test "returns changeset errors when data is invalid", %{user: user, node: node} do
|
||||
hub = create_team_hub(user, node)
|
||||
hub = connect_to_teams(user, node)
|
||||
teams_file_system = create_teams_file_system(hub, node)
|
||||
|
||||
file_system =
|
||||
|
|
@ -177,42 +204,64 @@ defmodule Livebook.HubsTest do
|
|||
|
||||
assert {:error, changeset} = Hubs.update_file_system(hub, update_file_system)
|
||||
assert "can't be blank" in errors_on(changeset).bucket_url
|
||||
refute_receive {:file_system_updated, _}
|
||||
end
|
||||
end
|
||||
|
||||
describe "delete_file_system/2" do
|
||||
test "deletes a file system", %{user: user, node: node} do
|
||||
hub = create_team_hub(user, node)
|
||||
teams_file_system = create_teams_file_system(hub, node)
|
||||
test "delete_file_system/2 deletes a file system", %{user: user, node: node} do
|
||||
hub = connect_to_teams(user, node)
|
||||
bucket_url = "https://#{hub.id}.s3.amazonaws.com"
|
||||
file_system = build(:fs_s3, bucket_url: bucket_url)
|
||||
|
||||
file_system =
|
||||
build(:fs_s3,
|
||||
bucket_url: teams_file_system.name,
|
||||
region: "us-east-1",
|
||||
external_id: to_string(teams_file_system.id)
|
||||
)
|
||||
assert Hubs.create_file_system(hub, file_system) == :ok
|
||||
assert_receive {:file_system_created, %{external_id: external_id} = file_system}
|
||||
assert file_system in Hubs.get_file_systems(hub)
|
||||
|
||||
assert Hubs.delete_file_system(hub, file_system) == :ok
|
||||
assert Hubs.delete_file_system(hub, file_system) == :ok
|
||||
assert_receive {:file_system_deleted, %{external_id: ^external_id}}
|
||||
refute file_system in Hubs.get_file_systems(hub)
|
||||
|
||||
# Guarantee it's been removed and will return HTTP status 404
|
||||
assert Hubs.delete_file_system(hub, file_system) ==
|
||||
{:transport_error,
|
||||
"Something went wrong, try again later or please file a bug if it persists"}
|
||||
end
|
||||
# Guarantee it's been removed and will return HTTP status 404
|
||||
assert Hubs.delete_file_system(hub, file_system) ==
|
||||
{:transport_error,
|
||||
"Something went wrong, try again later or please file a bug if it persists"}
|
||||
|
||||
test "returns transport errors when file system doesn't exists", %{user: user, node: node} do
|
||||
hub = create_team_hub(user, node)
|
||||
refute_receive {:file_system_deleted, _}
|
||||
end
|
||||
|
||||
file_system =
|
||||
build(:fs_s3,
|
||||
bucket_url: "https://i_cant_exist.s3.amazonaws.com",
|
||||
external_id: "123456789"
|
||||
)
|
||||
test "generates and verifies stamp for a notebook", %{user: user, node: node} do
|
||||
team = connect_to_teams(user, node)
|
||||
|
||||
# Guarantee it doesn't exists and will return HTTP status 404
|
||||
assert Hubs.delete_file_system(hub, file_system) ==
|
||||
{:transport_error,
|
||||
"Something went wrong, try again later or please file a bug if it persists"}
|
||||
end
|
||||
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 connect_to_teams(user, node) do
|
||||
%{id: id} = team = create_team_hub(user, node)
|
||||
assert_receive {:hub_connected, ^id}
|
||||
assert_receive {:client_connected, ^id}
|
||||
|
||||
team
|
||||
end
|
||||
|
||||
defp secret_name(%{id: id}) do
|
||||
id
|
||||
|> String.replace("-", "_")
|
||||
|> String.upcase()
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,226 +0,0 @@
|
|||
defmodule Livebook.Teams.ConnectionTest do
|
||||
alias Livebook.FileSystem
|
||||
use Livebook.TeamsIntegrationCase, async: true
|
||||
|
||||
alias Livebook.Teams.Connection
|
||||
|
||||
describe "connect" do
|
||||
test "successfully authenticates the websocket connection", %{user: user, node: node} do
|
||||
{_, headers} = build_team_headers(user, node)
|
||||
|
||||
assert {:ok, _conn} = Connection.start_link(self(), headers)
|
||||
assert_receive :connected
|
||||
end
|
||||
|
||||
test "rejects the websocket connection with invalid credentials", %{user: user} do
|
||||
headers = [
|
||||
{"x-user", to_string(user.id)},
|
||||
{"x-org", to_string(user.id)},
|
||||
{"x-org-key", to_string(user.id)},
|
||||
{"x-session-token", "foo"}
|
||||
]
|
||||
|
||||
assert {:ok, _conn} = Connection.start_link(self(), headers)
|
||||
|
||||
assert_receive {:server_error,
|
||||
"Your session is out-of-date. Please re-join the organization."}
|
||||
|
||||
assert {:ok, _conn} = Connection.start_link(self(), [])
|
||||
|
||||
assert_receive {:server_error,
|
||||
"Invalid request. Please re-join the organization and update Livebook if the issue persists."}
|
||||
end
|
||||
end
|
||||
|
||||
describe "handle events" do
|
||||
test "receives the secret_created event", %{user: user, node: node} do
|
||||
{hub, headers} = build_team_headers(user, node)
|
||||
|
||||
assert {:ok, _conn} = Connection.start_link(self(), headers)
|
||||
assert_receive :connected
|
||||
|
||||
# creates a new secret
|
||||
secret = build(:secret, name: "FOO", value: "BAR")
|
||||
assert Livebook.Hubs.create_secret(hub, secret) == :ok
|
||||
|
||||
# receives `{:event, :secret_created, secret_created}` event
|
||||
# without decrypting the value
|
||||
assert_receive {:event, :secret_created, secret_created}
|
||||
assert secret_created.name == secret.name
|
||||
refute secret_created.value == secret.value
|
||||
end
|
||||
|
||||
test "receives the file_system_created event", %{user: user, node: node} do
|
||||
{hub, headers} = build_team_headers(user, node)
|
||||
|
||||
assert {:ok, _conn} = Connection.start_link(self(), headers)
|
||||
assert_receive :connected
|
||||
|
||||
# creates a new file system
|
||||
file_system = build(:fs_s3, bucket_url: "https://file_system_created.s3.amazonaws.com")
|
||||
assert Livebook.Hubs.create_file_system(hub, file_system) == :ok
|
||||
type = Livebook.FileSystems.type(file_system)
|
||||
%{name: name} = FileSystem.external_metadata(file_system)
|
||||
|
||||
# receives `{:event, :file_system_created, file_system_created}` event
|
||||
# without decrypting the value
|
||||
assert_receive {:event, :file_system_created, file_system_created}
|
||||
assert file_system_created.name == name
|
||||
assert file_system_created.type == to_string(type)
|
||||
refute file_system_created.value == FileSystem.dump(file_system)
|
||||
assert is_binary(file_system_created.value)
|
||||
end
|
||||
|
||||
test "receives the deployment_group_created event", %{user: user, node: node} do
|
||||
{hub, headers} = build_team_headers(user, node)
|
||||
|
||||
assert {:ok, _conn} = Connection.start_link(self(), headers)
|
||||
assert_receive :connected
|
||||
|
||||
# creates a new deployment group with offline mode
|
||||
deployment_group = build(:deployment_group, name: "FOO", mode: :offline, clustering: :dns)
|
||||
|
||||
assert {:ok, _id} =
|
||||
Livebook.Teams.create_deployment_group(hub, deployment_group)
|
||||
|
||||
# deployment_group name and mode are not encrypted
|
||||
assert_receive {:event, :deployment_group_created, deployment_group_created}
|
||||
assert deployment_group_created.name == deployment_group.name
|
||||
assert String.to_existing_atom(deployment_group_created.mode) == deployment_group.mode
|
||||
|
||||
assert String.to_existing_atom(deployment_group_created.clustering) ==
|
||||
deployment_group.clustering
|
||||
|
||||
# since the deployment group is with offline mode, the agent key shouldn't exists
|
||||
assert deployment_group_created.agent_keys == []
|
||||
|
||||
# creates a new deployment group with online mode
|
||||
deployment_group = build(:deployment_group, name: "BAR", mode: :online, clustering: :dns)
|
||||
{:ok, _id} = Livebook.Teams.create_deployment_group(hub, deployment_group)
|
||||
|
||||
# deployment_group name and mode are not encrypted
|
||||
assert_receive {:event, :deployment_group_created, deployment_group_created}
|
||||
assert deployment_group_created.name == deployment_group.name
|
||||
assert String.to_existing_atom(deployment_group_created.mode) == deployment_group.mode
|
||||
|
||||
assert String.to_existing_atom(deployment_group_created.clustering) ==
|
||||
deployment_group.clustering
|
||||
|
||||
# receives the built-in agent key
|
||||
assert [agent_key] = deployment_group_created.agent_keys
|
||||
assert is_binary(agent_key.key)
|
||||
assert agent_key.deployment_group_id == deployment_group_created.id
|
||||
end
|
||||
|
||||
@tag :tmp_dir
|
||||
test "receives the app deployments list from user_connected event",
|
||||
%{user: user, node: node, tmp_dir: tmp_dir} do
|
||||
{hub, headers} = build_team_headers(user, node)
|
||||
|
||||
# creates a new deployment group
|
||||
deployment_group = build(:deployment_group, name: "BAZ", mode: :online)
|
||||
{:ok, id} = Livebook.Teams.create_deployment_group(hub, deployment_group)
|
||||
|
||||
# creates a new app deployment
|
||||
deployment_group_id = to_string(id)
|
||||
slug = Livebook.Utils.random_short_id()
|
||||
title = "MyNotebook3-#{slug}"
|
||||
app_settings = %{Livebook.Notebook.AppSettings.new() | slug: slug}
|
||||
|
||||
notebook = %{
|
||||
Livebook.Notebook.new()
|
||||
| app_settings: app_settings,
|
||||
name: title,
|
||||
hub_id: hub.id,
|
||||
deployment_group_id: deployment_group_id
|
||||
}
|
||||
|
||||
files_dir = Livebook.FileSystem.File.local(tmp_dir)
|
||||
|
||||
{:ok, %Livebook.Teams.AppDeployment{} = app_deployment} =
|
||||
Livebook.Teams.AppDeployment.new(notebook, files_dir)
|
||||
|
||||
# since we want to fetch the app deployment from connection event,
|
||||
# we need to persist it before we connect to the WebSocket
|
||||
:ok = Livebook.Teams.deploy_app(hub, app_deployment)
|
||||
|
||||
assert {:ok, _conn} = Connection.start_link(self(), headers)
|
||||
assert_receive :connected
|
||||
|
||||
assert_receive {:event, :user_connected, user_connected}
|
||||
assert [app_deployment2] = user_connected.app_deployments
|
||||
assert app_deployment2.title == title
|
||||
assert app_deployment2.slug == slug
|
||||
assert app_deployment2.sha == app_deployment.sha
|
||||
assert app_deployment2.deployment_group_id == deployment_group_id
|
||||
end
|
||||
|
||||
@tag :tmp_dir
|
||||
test "receives the app deployments list from agent_connected event",
|
||||
%{user: user, node: node, tmp_dir: tmp_dir} do
|
||||
# To create a new app deployment, we need use the User connection
|
||||
{hub, _headers} = build_team_headers(user, node)
|
||||
|
||||
# creates a new deployment group
|
||||
deployment_group = build(:deployment_group, name: "BAZ", mode: :online)
|
||||
{:ok, id} = Livebook.Teams.create_deployment_group(hub, deployment_group)
|
||||
teams_deployment_group = erpc_call(node, :get_deployment_group!, [id])
|
||||
[teams_agent_key] = teams_deployment_group.agent_keys
|
||||
|
||||
# creates a new app deployment
|
||||
slug = Livebook.Utils.random_short_id()
|
||||
title = "MyNotebook3-#{slug}"
|
||||
app_settings = %{Livebook.Notebook.AppSettings.new() | slug: slug}
|
||||
|
||||
notebook = %{
|
||||
Livebook.Notebook.new()
|
||||
| app_settings: app_settings,
|
||||
name: title,
|
||||
hub_id: hub.id,
|
||||
deployment_group_id: to_string(id)
|
||||
}
|
||||
|
||||
files_dir = Livebook.FileSystem.File.local(tmp_dir)
|
||||
|
||||
{:ok, %Livebook.Teams.AppDeployment{} = app_deployment} =
|
||||
Livebook.Teams.AppDeployment.new(notebook, files_dir)
|
||||
|
||||
# since we want to fetch the app deployment from connection event,
|
||||
# we need to persist it before we connect to the WebSocket
|
||||
:ok = Livebook.Teams.deploy_app(hub, app_deployment)
|
||||
|
||||
# As we need to be Agent to receive the app deployments list to be deployed,
|
||||
# we will create another connection here
|
||||
public_key = hub.org_public_key
|
||||
|
||||
hub = %{
|
||||
hub
|
||||
| user_id: nil,
|
||||
org_public_key: nil,
|
||||
session_token: teams_agent_key.key
|
||||
}
|
||||
|
||||
agent_name = Livebook.Config.agent_name()
|
||||
|
||||
headers = [
|
||||
{"x-lb-version", Livebook.Config.app_version()},
|
||||
{"x-org", to_string(hub.org_id)},
|
||||
{"x-org-key", to_string(hub.org_key_id)},
|
||||
{"x-agent-name", agent_name},
|
||||
{"x-agent-key", hub.session_token}
|
||||
]
|
||||
|
||||
assert {:ok, _conn} = Connection.start_link(self(), headers)
|
||||
assert_receive :connected
|
||||
|
||||
assert_receive {:event, :agent_connected, agent_connected}
|
||||
assert agent_connected.name == agent_name
|
||||
assert agent_connected.public_key == public_key
|
||||
assert [app_deployment2] = agent_connected.app_deployments
|
||||
assert app_deployment2.title == title
|
||||
assert app_deployment2.slug == slug
|
||||
assert app_deployment2.sha == app_deployment.sha
|
||||
assert app_deployment2.deployment_group_id == to_string(id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,9 +1,16 @@
|
|||
defmodule Livebook.TeamsTest do
|
||||
use Livebook.TeamsIntegrationCase, async: true
|
||||
|
||||
alias Livebook.{Notebook, Teams, Utils}
|
||||
alias Livebook.{FileSystem, Notebook, Teams, Utils}
|
||||
alias Livebook.Teams.Org
|
||||
|
||||
setup do
|
||||
Livebook.Hubs.Broadcasts.subscribe([:connection, :file_systems, :secrets])
|
||||
Livebook.Teams.Broadcasts.subscribe([:clients, :deployment_groups, :app_deployments, :agents])
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
describe "create_org/1" do
|
||||
test "returns the device flow data to confirm the org creation" do
|
||||
org = build(:org)
|
||||
|
|
@ -161,10 +168,17 @@ defmodule Livebook.TeamsTest do
|
|||
|
||||
describe "create_deployment_group/2" do
|
||||
test "creates a new deployment group when the data is valid", %{user: user, node: node} do
|
||||
team = create_team_hub(user, node)
|
||||
deployment_group = build(:deployment_group)
|
||||
team = connect_to_teams(user, node)
|
||||
|
||||
assert {:ok, _id} = Teams.create_deployment_group(team, deployment_group)
|
||||
deployment_group =
|
||||
build(:deployment_group, name: "DEPLOYMENT_GROUP_#{team.id}", mode: :online)
|
||||
|
||||
assert {:ok, id} = Teams.create_deployment_group(team, deployment_group)
|
||||
|
||||
%{name: name, mode: mode} = deployment_group
|
||||
id = to_string(id)
|
||||
|
||||
assert_receive {:deployment_group_created, %{id: ^id, name: ^name, mode: ^mode}}
|
||||
|
||||
# Guarantee uniqueness
|
||||
assert {:error, changeset} = Teams.create_deployment_group(team, deployment_group)
|
||||
|
|
@ -172,50 +186,69 @@ defmodule Livebook.TeamsTest do
|
|||
end
|
||||
|
||||
test "returns changeset errors when the name is invalid", %{user: user, node: node} do
|
||||
team = create_team_hub(user, node)
|
||||
team = connect_to_teams(user, node)
|
||||
deployment_group = %{build(:deployment_group) | name: ""}
|
||||
|
||||
assert {:error, changeset} = Teams.create_deployment_group(team, deployment_group)
|
||||
assert "can't be blank" in errors_on(changeset).name
|
||||
refute_receive {:deployment_group_created, _}
|
||||
end
|
||||
|
||||
test "returns changeset errors when the mode is invalid", %{user: user, node: node} do
|
||||
team = create_team_hub(user, node)
|
||||
team = connect_to_teams(user, node)
|
||||
deployment_group = %{build(:deployment_group) | mode: "invalid"}
|
||||
|
||||
assert {:error, changeset} = Teams.create_deployment_group(team, deployment_group)
|
||||
assert "is invalid" in errors_on(changeset).mode
|
||||
refute_receive {:deployment_group_created, _}
|
||||
end
|
||||
end
|
||||
|
||||
describe "deploy_app/2" do
|
||||
@tag :tmp_dir
|
||||
test "deploys app to Teams from a notebook", %{user: user, node: node, tmp_dir: tmp_dir} do
|
||||
team = create_team_hub(user, node)
|
||||
team = connect_to_teams(user, node)
|
||||
deployment_group = build(:deployment_group, name: "BAZ", mode: :online)
|
||||
|
||||
{:ok, id} = Teams.create_deployment_group(team, deployment_group)
|
||||
|
||||
app_settings = %{Notebook.AppSettings.new() | slug: Utils.random_short_id()}
|
||||
id = to_string(id)
|
||||
assert_receive {:deployment_group_created, %{id: ^id}}
|
||||
|
||||
# creates the app deployment
|
||||
slug = Utils.random_short_id()
|
||||
title = "MyNotebook-#{slug}"
|
||||
app_settings = %{Notebook.AppSettings.new() | slug: slug}
|
||||
|
||||
notebook = %{
|
||||
Notebook.new()
|
||||
| app_settings: app_settings,
|
||||
name: "MyNotebook",
|
||||
name: title,
|
||||
hub_id: team.id,
|
||||
deployment_group_id: to_string(id)
|
||||
deployment_group_id: id
|
||||
}
|
||||
|
||||
files_dir = Livebook.FileSystem.File.local(tmp_dir)
|
||||
|
||||
files_dir = FileSystem.File.local(tmp_dir)
|
||||
assert {:ok, app_deployment} = Teams.AppDeployment.new(notebook, files_dir)
|
||||
assert Teams.deploy_app(team, app_deployment) == :ok
|
||||
|
||||
sha = app_deployment.sha
|
||||
multi_session = app_settings.multi_session
|
||||
access_type = app_settings.access_type
|
||||
|
||||
assert_receive {:app_deployment_started,
|
||||
%Livebook.Teams.AppDeployment{
|
||||
slug: ^slug,
|
||||
sha: ^sha,
|
||||
title: ^title,
|
||||
multi_session: ^multi_session,
|
||||
access_type: ^access_type,
|
||||
deployment_group_id: ^id
|
||||
} = app_deployment2}
|
||||
|
||||
assert {:error,
|
||||
%{errors: [slug: {"should only contain alphanumeric characters and dashes", []}]}} =
|
||||
Teams.deploy_app(team, %{app_deployment | slug: "@abc"})
|
||||
|
||||
# Since the fields below belongs to AppSettings, we're mapping the errors to `:file` field.
|
||||
assert {:error, %{errors: [multi_session: {"can't be blank", []}]}} =
|
||||
Teams.deploy_app(team, %{app_deployment | multi_session: nil})
|
||||
|
||||
|
|
@ -224,6 +257,18 @@ defmodule Livebook.TeamsTest do
|
|||
|
||||
assert {:error, %{errors: [access_type: {"is invalid", []}]}} =
|
||||
Teams.deploy_app(team, %{app_deployment | access_type: :abc})
|
||||
|
||||
# force app deployment to be stopped
|
||||
erpc_call(node, :toggle_app_deployment, [app_deployment2.id, team.org_id])
|
||||
assert_receive {:app_deployment_stopped, ^app_deployment2}
|
||||
end
|
||||
end
|
||||
|
||||
defp connect_to_teams(user, node) do
|
||||
%{id: id} = team = create_team_hub(user, node)
|
||||
assert_receive {:hub_connected, ^id}
|
||||
assert_receive {:client_connected, ^id}
|
||||
|
||||
team
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue