Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Increase test coverage #1277

Merged
merged 1 commit into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions lib/realtime/api/tenant.ex
Original file line number Diff line number Diff line change
Expand Up @@ -102,16 +102,4 @@ defmodule Realtime.Api.Tenant do
def encrypt_jwt_secret(changeset) do
update_change(changeset, :jwt_secret, &Crypto.encrypt!/1)
end

def management_changeset(tenant, attrs) do
cast(tenant, attrs, [
:max_concurrent_users,
:max_events_per_second,
:max_bytes_per_second,
:max_channels_per_client,
:max_joins_per_second,
:suspend,
:private_only
])
end
end
19 changes: 0 additions & 19 deletions lib/realtime/tenants.ex
Original file line number Diff line number Diff line change
Expand Up @@ -272,25 +272,6 @@ defmodule Realtime.Tenants do
|> tap(fn _ -> broadcast_operation_event(:unsuspend_tenant, external_id) end)
end

@doc """
Changes only information regading user managent:
:max_concurrent_users
:max_events_per_second
:max_bytes_per_second
:max_channels_per_client
:max_joins_per_second
:suspend
:private_only
"""
@spec update_management(String.t(), map()) :: Tenant.t() | nil
def update_management(tenant_id, attrs) do
tenant_id
|> Cache.get_tenant_by_external_id()
|> Tenant.management_changeset(attrs)
|> Repo.update!()
|> tap(fn _ -> Cache.invalidate_tenant_cache(tenant_id) end)
end

defp broadcast_operation_event(action, external_id) do
Phoenix.PubSub.broadcast!(
Realtime.PubSub,
Expand Down
1 change: 0 additions & 1 deletion lib/realtime_web/channels/realtime_channel.ex
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,6 @@ defmodule RealtimeWeb.RealtimeChannel do
shutdown_response(socket, msg)

{:error, error} ->
IO.inspect(error)
msg = "Received an invalid access token from client: " <> inspect(error)

shutdown_response(socket, msg)
Expand Down
16 changes: 0 additions & 16 deletions lib/realtime_web/controllers/tenant_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@
subs_id = UserSocket.subscribers_id(tenant_id)

with %Tenant{} = tenant <- Api.get_tenant_by_external_id(tenant_id, :primary),
_ <- Realtime.Tenants.Connect.shutdown(tenant_id),

Check warning on line 193 in lib/realtime_web/controllers/tenant_controller.ex

View workflow job for this annotation

GitHub Actions / Tests

Nested modules could be aliased at the top of the invoking module.
true <- Api.delete_tenant_by_external_id(tenant_id),
:ok <- Cache.distributed_invalidate_tenant_cache(tenant_id),
:ok <- PostgresCdc.stop_all(tenant, stop_all_timeout),
Expand Down Expand Up @@ -283,20 +283,4 @@
|> render("not_found.json", tenant: nil)
end
end

def patch(conn, %{"tenant_id" => tenant_id} = attrs) do
Logger.metadata(external_id: tenant_id, project: tenant_id)

case Tenants.update_management(tenant_id, attrs) do
%Tenant{} = tenant ->
render(conn, "show.json", tenant: tenant)

nil ->
log_error("TenantNotFound", "Tenant not found")

conn
|> put_status(404)
|> render("not_found.json", tenant: nil)
end
end
end
24 changes: 0 additions & 24 deletions lib/realtime_web/live/admin_live/index.ex

This file was deleted.

2 changes: 0 additions & 2 deletions lib/realtime_web/live/admin_live/index.html.heex

This file was deleted.

15 changes: 2 additions & 13 deletions lib/realtime_web/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,7 @@ defmodule RealtimeWeb.Router do
end

scope "/admin", RealtimeWeb do
pipe_through(:browser)

unless Mix.env() in [:dev, :test] do
pipe_through(:dashboard_admin)
end

live("/", AdminLive.Index, :index)
pipe_through [:browser, :dashboard_admin]
live("/tenants", TenantsLive.Index, :index)
end

Expand All @@ -92,7 +86,6 @@ defmodule RealtimeWeb.Router do
resources("/tenants", TenantController, param: "tenant_id", except: [:edit, :new])
post("/tenants/:tenant_id/reload", TenantController, :reload)
get("/tenants/:tenant_id/health", TenantController, :health)
patch("/tenants/:tenant_id/management", TenantController, :patch)
end

scope "/api", RealtimeWeb do
Expand All @@ -115,11 +108,7 @@ defmodule RealtimeWeb.Router do
# you can use Plug.BasicAuth to set up some basic authentication
# as long as you are also using SSL (which you should anyway).
scope "/admin" do
pipe_through(:browser)

unless Mix.env() in [:dev, :test] do
pipe_through(:dashboard_admin)
end
pipe_through [:browser, :dashboard_admin]

live_dashboard("/dashboard",
ecto_repos: [
Expand Down
5 changes: 3 additions & 2 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ defmodule Realtime.MixProject do
def project do
[
app: :realtime,
version: "2.34.4",
version: "2.34.5",
elixir: "~> 1.17.3",
elixirc_paths: elixirc_paths(Mix.env()),
start_permanent: Mix.env() == :prod,
Expand Down Expand Up @@ -78,7 +78,8 @@ defmodule Realtime.MixProject do
{:mint_web_socket, "~> 1.0", only: :test},
{:dialyxir, "~> 1.4", only: :dev, runtime: false},
{:benchee, "~> 1.1.0", only: :dev},
{:excoveralls, "~> 0.18", only: [:dev, :test], runtime: false}
{:excoveralls, "~> 0.18", only: [:dev, :test], runtime: false},
{:floki, ">= 0.30.0", only: :test}
]
end

Expand Down
1 change: 1 addition & 0 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"expo": {:hex, :expo, "1.1.0", "f7b9ed7fb5745ebe1eeedf3d6f29226c5dd52897ac67c0f8af62a07e661e5c75", [:mix], [], "hexpm", "fbadf93f4700fb44c331362177bdca9eeb8097e8b0ef525c9cc501cb9917c960"},
"file_system": {:hex, :file_system, "1.1.0", "08d232062284546c6c34426997dd7ef6ec9f8bbd090eb91780283c9016840e8f", [:mix], [], "hexpm", "bfcf81244f416871f2a2e15c1b515287faa5db9c6bcf290222206d120b3d43f6"},
"finch": {:hex, :finch, "0.19.0", "c644641491ea854fc5c1bbaef36bfc764e3f08e7185e1f084e35e0672241b76d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.6.2 or ~> 1.7", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "fc5324ce209125d1e2fa0fcd2634601c52a787aff1cd33ee833664a5af4ea2b6"},
"floki": {:hex, :floki, "0.37.0", "b83e0280bbc6372f2a403b2848013650b16640cd2470aea6701f0632223d719e", [:mix], [], "hexpm", "516a0c15a69f78c47dc8e0b9b3724b29608aa6619379f91b1ffa47109b5d0dd3"},
"gettext": {:hex, :gettext, "0.26.2", "5978aa7b21fada6deabf1f6341ddba50bc69c999e812211903b169799208f2a8", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "aa978504bcf76511efdc22d580ba08e2279caab1066b76bb9aa81c4a1e0a32a5"},
"hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"},
"hpax": {:hex, :hpax, "1.0.2", "762df951b0c399ff67cc57c3995ec3cf46d696e41f0bba17da0518d94acd4aac", [:mix], [], "hexpm", "2f09b4c1074e0abd846747329eaa26d535be0eb3d189fa69d812bfb8bfefd32f"},
Expand Down
25 changes: 18 additions & 7 deletions test/integration/rt_channel_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -858,8 +858,8 @@
test "user with only private channels enabled will not be able to join public channels", %{
topic: topic
} do
Realtime.Tenants.update_management(@external_id, %{private_only: true})
Process.sleep(100)
set_private_only(true)

{socket, _} = get_connection("authenticated")
config = %{broadcast: %{self: true}, private: false}
topic = "realtime:#{topic}"
Expand All @@ -874,8 +874,7 @@
},
500

Realtime.Tenants.update_management(@external_id, %{private_only: false})
Process.sleep(100)
set_private_only(false)
end

@tag policies: [
Expand All @@ -885,16 +884,19 @@
test "user with only private channels enabled will be able to join private channels", %{
topic: topic
} do
Realtime.Tenants.update_management(@external_id, %{private_only: true})
set_private_only(true)

Realtime.Tenants.Cache.invalidate_tenant_cache(@external_id)

Check warning on line 889 in test/integration/rt_channel_test.exs

View workflow job for this annotation

GitHub Actions / Tests

Nested modules could be aliased at the top of the invoking module.

Process.sleep(100)

{socket, _} = get_connection("authenticated")
config = %{broadcast: %{self: true}, private: true}
topic = "realtime:#{topic}"
WebsocketClient.join(socket, topic, %{config: config})

assert_receive %Phoenix.Socket.Message{event: "phx_reply"}, 500
Realtime.Tenants.update_management(@external_id, %{private_only: false})
Process.sleep(100)
set_private_only(false)
end
end

Expand Down Expand Up @@ -1046,10 +1048,10 @@
end

def setup_trigger(%{tenant: tenant, topic: topic} = context) do
Realtime.Tenants.Connect.shutdown(@external_id)

Check warning on line 1051 in test/integration/rt_channel_test.exs

View workflow job for this annotation

GitHub Actions / Tests

Nested modules could be aliased at the top of the invoking module.
Process.sleep(500)

{:ok, db_conn} = Realtime.Tenants.Connect.connect(@external_id)

Check warning on line 1054 in test/integration/rt_channel_test.exs

View workflow job for this annotation

GitHub Actions / Tests

Nested modules could be aliased at the top of the invoking module.

random_name = String.downcase("test_#{random_string()}")
query = "CREATE TABLE #{random_name} (id serial primary key, details text)"
Expand Down Expand Up @@ -1086,7 +1088,7 @@
{:ok, db_conn} = Database.connect(tenant, "realtime_test", :stop)
query = "DROP TABLE #{random_name} CASCADE"
Postgrex.query!(db_conn, query, [])
Realtime.Tenants.Connect.shutdown(db_conn)

Check warning on line 1091 in test/integration/rt_channel_test.exs

View workflow job for this annotation

GitHub Actions / Tests

Nested modules could be aliased at the top of the invoking module.

Process.sleep(500)
end)
Expand All @@ -1095,4 +1097,13 @@
|> Map.put(:db_conn, db_conn)
|> Map.put(:table_name, random_name)
end

defp set_private_only(value) do
@external_id
|> Realtime.Tenants.get_tenant_by_external_id()
|> Realtime.Api.Tenant.changeset(%{private_only: value})

Check warning on line 1104 in test/integration/rt_channel_test.exs

View workflow job for this annotation

GitHub Actions / Tests

Nested modules could be aliased at the top of the invoking module.
|> Realtime.Repo.update!()

Realtime.Tenants.Cache.invalidate_tenant_cache(@external_id)

Check warning on line 1107 in test/integration/rt_channel_test.exs

View workflow job for this annotation

GitHub Actions / Tests

Nested modules could be aliased at the top of the invoking module.
end
end
16 changes: 0 additions & 16 deletions test/realtime/tenants_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -70,20 +70,4 @@ defmodule Realtime.TenantsTest do
assert_receive {:unsuspend_tenant, ^external_id}, 1000
end
end

describe "update_management/2" do
setup do
tenant = tenant_fixture()
topic = "realtime:operations:invalidate_cache"
Phoenix.PubSub.subscribe(Realtime.PubSub, topic)
%{topic: topic, tenant: tenant}
end

test "sets private_only flag to true and invalidates cache" do
%{external_id: external_id} = tenant_fixture(%{private_only: false})
tenant = Tenants.update_management(external_id, %{private_only: true})
assert tenant.private_only
assert Tenants.Cache.get_tenant_by_external_id(external_id).private_only
end
end
end
46 changes: 46 additions & 0 deletions test/realtime_web/controllers/live_dasboard_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
defmodule RealtimeWeb.LiveDashboardTest do
use RealtimeWeb.ConnCase
import Generators

describe "live_dashboard" do
setup do
user = random_string()
password = random_string()

System.put_env("DASHBOARD_USER", user)
System.put_env("DASHBOARD_PASSWORD", password)

on_exit(fn ->
System.delete_env("DASHBOARD_USER")
System.delete_env("DASHBOARD_PASSWORD")
end)

%{user: user, password: password}
end

test "with credetentials renders view", %{
conn: conn,
user: user,
password: password
} do
path =
conn
|> using_basic_auth(user, password)
|> get("/admin/dashboard")
|> redirected_to(302)

conn = conn |> recycle() |> using_basic_auth(user, password) |> get(path)

assert html_response(conn, 200) =~ "Dashboard"
end

test "without credetentials returns 401", %{conn: conn} do
assert conn |> get("/admin/dashboard") |> response(401)
end
end

defp using_basic_auth(conn, username, password) do
header_content = "Basic " <> Base.encode64("#{username}:#{password}")
put_req_header(conn, "authorization", header_content)
end
end
17 changes: 17 additions & 0 deletions test/realtime_web/controllers/openapi_controller_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
defmodule RealtimeWeb.Controllers.OpenapiControllerTest do
use RealtimeWeb.ConnCase

describe "openapi" do
test "returns the openapi spec", %{conn: conn} do
conn = get(conn, ~p"/api/openapi")
assert json_response(conn, 200)
end
end

describe "swaggerui" do
test "returns the swaggerui", %{conn: conn} do
conn = get(conn, ~p"/swaggerui")
assert html_response(conn, 200) =~ "Swagger UI"
end
end
end
13 changes: 13 additions & 0 deletions test/realtime_web/controllers/page_controller_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
defmodule RealtimeWeb.PageControllerTest do
use RealtimeWeb.ConnCase

test "GET / renders index page", %{conn: conn} do
conn = get(conn, "/")
assert html_response(conn, 200) =~ " Supabase Realtime: Multiplayer Edition"
end

test "GET /healthcheck returns ok status", %{conn: conn} do
conn = get(conn, "/healthcheck")
assert text_response(conn, 200) == "ok"
end
end
Loading
Loading