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: Improve coverage of Realtime.API tests #642

Merged
merged 1 commit into from
Aug 22, 2023
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
7 changes: 7 additions & 0 deletions lib/realtime/api.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import Ecto.Query

alias Realtime.{Repo, Api.Tenant, Api.Extensions, RateCounter, GenCounter, Tenants}

Check warning on line 9 in lib/realtime/api.ex

View workflow job for this annotation

GitHub Actions / Formatting Checks

The alias `Realtime.Repo` is not alphabetically ordered among its group.

@doc """
Returns the list of tenants.
Expand All @@ -25,6 +25,13 @@
|> repo_replica.preload(:extensions)
end

@doc """
Returns list of tenants with filter options:
* order_by
* search external id
* limit
* ordering (desc / asc)
"""
def list_tenants(opts) when is_list(opts) do
repo_replica = Repo.replica()

Expand Down
2 changes: 1 addition & 1 deletion 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.20.3",
version: "2.20.4",
elixir: "~> 1.14.0",
elixirc_paths: elixirc_paths(Mix.env()),
start_permanent: Mix.env() == :prod,
Expand Down
189 changes: 98 additions & 91 deletions test/realtime/api_test.exs
Original file line number Diff line number Diff line change
@@ -1,73 +1,90 @@
defmodule Realtime.ApiTest do
use Realtime.DataCase
use Realtime.DataCase, async: false

import Mock

alias Realtime.Api
alias Realtime.{Api, RateCounter, GenCounter}
alias Realtime.Api.Extensions
alias Realtime.Api.Tenant
alias Realtime.GenCounter
alias Realtime.RateCounter

@db_conf Application.compile_env(:realtime, Realtime.Repo)

@valid_attrs %{
external_id: "external_id",
name: "localhost",
extensions: [
%{
"type" => "postgres_cdc_rls",
"settings" => %{
"db_host" => @db_conf[:hostname],
"db_name" => @db_conf[:database],
"db_user" => @db_conf[:username],
"db_password" => @db_conf[:password],
"db_port" => "5432",
"poll_interval" => 100,
"poll_max_changes" => 100,
"poll_max_record_bytes" => 1_048_576,
"region" => "us-east-1"
}
}
],
postgres_cdc_default: "postgres_cdc_rls",
jwt_secret: "new secret",
max_concurrent_users: 200,
max_events_per_second: 100
}

@update_attrs %{
external_id: "external_id1",
jwt_secret: "some updated jwt_secret",
name: "some updated name"
}
@invalid_attrs %{external_id: nil, jwt_secret: nil, name: nil}

setup do
tenants = [
tenant_fixture(%{external_id: "external_id1", max_concurrent_users: 10}),
tenant_fixture(%{external_id: "external_id2", max_concurrent_users: 5}),
tenant_fixture(%{external_id: "external_id3", max_concurrent_users: 15}),
tenant_fixture(%{external_id: "external_id4", max_concurrent_users: 20}),
tenant_fixture(%{external_id: "external_id5", max_concurrent_users: 25})
]

dev_tenant = Api.list_tenants(search: "dev_tenant")
tenants = tenants ++ dev_tenant

%{tenants: tenants}
end

describe "tenants" do
alias Realtime.Api.{Tenant, Extensions}
db_conf = Application.compile_env(:realtime, Realtime.Repo)

@valid_attrs %{
external_id: "external_id",
name: "localhost",
extensions: [
%{
"type" => "postgres_cdc_rls",
"settings" => %{
"db_host" => db_conf[:hostname],
"db_name" => db_conf[:database],
"db_user" => db_conf[:username],
"db_password" => db_conf[:password],
"db_port" => "5432",
"poll_interval" => 100,
"poll_max_changes" => 100,
"poll_max_record_bytes" => 1_048_576,
"region" => "us-east-1"
}
}
],
postgres_cdc_default: "postgres_cdc_rls",
jwt_secret: "new secret",
max_concurrent_users: 200,
max_events_per_second: 100
}

@update_attrs %{
external_id: "external_id",
jwt_secret: "some updated jwt_secret",
name: "some updated name"
}
@invalid_attrs %{external_id: nil, jwt_secret: nil, name: nil}

def tenant_fixture(attrs \\ %{}) do
{:ok, tenant} =
attrs
|> Enum.into(@valid_attrs)
|> Api.create_tenant()

tenant
test "list_tenants/0 returns all tenants", %{tenants: tenants} do
assert Enum.sort(Api.list_tenants()) == Enum.sort(tenants)
end

test "list_tenants/0 returns all tenants" do
tenant = tenant_fixture()
test "list_tenants/1 returns filtered tenants", %{tenants: tenants} do
assert hd(Api.list_tenants(search: hd(tenants).external_id)) == hd(tenants)

assert Api.list_tenants() |> Enum.filter(fn e -> e.external_id == "external_id" end) == [
tenant
]
end
assert Api.list_tenants(order_by: "max_concurrent_users") ==
Enum.sort_by(tenants, & &1.max_concurrent_users, :desc)

test "get_tenant!/1 returns the tenant with given id" do
tenant = tenant_fixture()
assert Api.list_tenants(order_by: "max_concurrent_users", order: "asc") ==
Enum.sort_by(tenants, & &1.max_concurrent_users, :asc)

assert Api.get_tenant!(tenant.id) |> Map.delete(:extensions) ==
tenant |> Map.delete(:extensions)
assert Api.list_tenants(order_by: "max_concurrent_users", order: "asc", limit: 2) ==
tenants |> Enum.sort_by(& &1.max_concurrent_users, :asc) |> Enum.take(2)
end

test "get_tenant!/1 returns the tenant with given id", %{tenants: [tenant | _]} do
result = Api.get_tenant!(tenant.id) |> Map.delete(:extensions)
expected = tenant |> Map.delete(:extensions)
assert result == expected
end

test "create_tenant/1 with valid data creates a tenant" do
assert {:ok, %Tenant{} = tenant} = Api.create_tenant(@valid_attrs)

assert tenant.external_id == "external_id"
assert tenant.jwt_secret == "YIriPuuJO1uerq5hSZ1W5Q=="
assert tenant.name == "localhost"
Expand All @@ -77,73 +94,54 @@ defmodule Realtime.ApiTest do
assert {:error, %Ecto.Changeset{}} = Api.create_tenant(@invalid_attrs)
end

test "check get_tenant_by_external_id/1" do
tenant_fixture()

test "check get_tenant_by_external_id/1", %{tenants: [tenant | _]} do
%Tenant{extensions: [%Extensions{} = extension]} =
Api.get_tenant_by_external_id("external_id")
Api.get_tenant_by_external_id(tenant.external_id)

assert Map.has_key?(extension.settings, "db_password")
password = extension.settings["db_password"]
assert ^password = "v1QVng3N+pZd/0AEObABwg=="
end

test "update_tenant/2 with valid data updates the tenant" do
tenant = tenant_fixture()
assert {:ok, %Tenant{} = tenant} = Api.update_tenant(tenant, @update_attrs)
assert tenant.external_id == "external_id"
test "update_tenant/2 with valid data updates the tenant", %{tenants: [tenant | _]} do
db_enc_key = Application.get_env(:realtime, :db_enc_key)

assert tenant.jwt_secret ==
Realtime.Helpers.encrypt!(
"some updated jwt_secret",
Application.get_env(:realtime, :db_enc_key)
)
assert {:ok, %Tenant{} = tenant} = Api.update_tenant(tenant, @update_attrs)
assert tenant.external_id == "external_id1"

assert tenant.jwt_secret == Realtime.Helpers.encrypt!("some updated jwt_secret", db_enc_key)
assert tenant.name == "some updated name"
end

test "update_tenant/2 with invalid data returns error changeset" do
tenant = tenant_fixture()
test "update_tenant/2 with invalid data returns error changeset", %{tenants: [tenant | _]} do
assert {:error, %Ecto.Changeset{}} = Api.update_tenant(tenant, @invalid_attrs)
end

test "delete_tenant/1 deletes the tenant" do
tenant = tenant_fixture()
test "delete_tenant/1 deletes the tenant", %{tenants: [tenant | _]} do
assert {:ok, %Tenant{}} = Api.delete_tenant(tenant)
assert_raise Ecto.NoResultsError, fn -> Api.get_tenant!(tenant.id) end
end

test "delete_tenant_by_external_id/1 deletes the tenant" do
tenant = tenant_fixture()
test "delete_tenant_by_external_id/1 deletes the tenant", %{tenants: [tenant | _]} do
assert true == Api.delete_tenant_by_external_id(tenant.external_id)
assert false == Api.delete_tenant_by_external_id("undef_tenant")
assert_raise Ecto.NoResultsError, fn -> Api.get_tenant!(tenant.id) end
end

test "change_tenant/1 returns a tenant changeset" do
tenant = tenant_fixture()
test "change_tenant/1 returns a tenant changeset", %{tenants: [tenant | _]} do
assert %Ecto.Changeset{} = Api.change_tenant(tenant)
end

test "list_extensions/1 " do
assert length(Api.list_extensions()) == 1
test "list_extensions/1 ", %{tenants: tenants} do
assert length(Api.list_extensions()) == length(tenants)
end

test "preload_counters/1 " do
tenant = tenant_fixture()
test "preload_counters/1 ", %{tenants: [tenant | _]} do
assert Api.preload_counters(nil) == nil

with_mocks([
{GenCounter, [],
[
get: fn _ ->
{:ok, 1}
end
]},
{RateCounter, [],
[
get: fn _ -> {:ok, %RateCounter{avg: 2}} end
]}
{GenCounter, [], [get: fn _ -> {:ok, 1} end]},
{RateCounter, [], [get: fn _ -> {:ok, %RateCounter{avg: 2}} end]}
]) do
counters = Api.preload_counters(tenant)
assert counters.events_per_second_rolling == 2
Expand All @@ -153,9 +151,18 @@ defmodule Realtime.ApiTest do
assert Api.preload_counters(nil, :any) == nil
end

test "rename_settings_field/2" do
test "rename_settings_field/2", %{tenants: [tenant | _]} do
Api.rename_settings_field("poll_interval_ms", "poll_interval")
assert %{extensions: [%{settings: %{"poll_interval" => _}}]} = tenant_fixture()
assert %{extensions: [%{settings: %{"poll_interval" => _}}]} = tenant
end
end

defp tenant_fixture(attrs) do
{:ok, tenant} =
attrs
|> Enum.into(@valid_attrs)
|> Api.create_tenant()

tenant
end
end
Loading