Skip to content

Commit

Permalink
Implement postgres in CI for ResourceQuery tests
Browse files Browse the repository at this point in the history
  • Loading branch information
brandonjoyce committed May 7, 2024
1 parent d864ea1 commit 88834e2
Show file tree
Hide file tree
Showing 14 changed files with 379 additions and 85 deletions.
64 changes: 34 additions & 30 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,30 @@ name: Kaffy CI (Elixir)

on:
push:
branches: [ master ]
branches: [master]
pull_request:
branches: [ master ]
branches: [master]

jobs:
test:
name: Test ${{matrix.otp}} / Elixir ${{matrix.elixir}}
runs-on: ubuntu-20.04
strategy:
matrix:
otp: ['22', '23', '24', '25']
elixir: ['1.12.3', '1.13.4', '1.14.5', '1.15.5']
otp: ["22", "23", "24", "25"]
elixir: ["1.12.3", "1.13.4", "1.14.5", "1.15.5"]
# Exclude invalid combinations of Elixir and OTP
exclude:
- otp: '22'
elixir: '1.14.5'
- otp: '22'
elixir: '1.15.5'
- otp: '23'
elixir: '1.15.5'
- otp: '25'
elixir: '1.12.3'
- otp: '25'
elixir: '1.13.4'
- otp: "22"
elixir: "1.14.5"
- otp: "22"
elixir: "1.15.5"
- otp: "23"
elixir: "1.15.5"
- otp: "25"
elixir: "1.12.3"
- otp: "25"
elixir: "1.13.4"
# Include the release candidate for the next Elixir, but don't
# fail CI.
# include:
Expand All @@ -34,19 +34,23 @@ jobs:
# experimental: true

steps:
- uses: actions/checkout@v3
- name: Set up Elixir
uses: erlef/setup-beam@v1
with:
elixir-version: ${{matrix.elixir}} # Define the elixir version [required]
otp-version: ${{matrix.otp}} # Define the OTP version [required]
- name: Restore dependencies cache
uses: actions/cache@v2
with:
path: deps
key: ${{ runner.os }}-${{ matrix.elixir }}-${{ matrix.otp }}-mix-${{ hashFiles('**/mix.lock') }}
restore-keys: ${{ runner.os }}-${{ matrix.elixir }}-${{ matrix.otp }}-mix-
- name: Install dependencies
run: mix deps.get
- name: Run tests
run: mix test
- uses: actions/checkout@v3
- name: Set up Elixir
uses: erlef/setup-beam@v1
with:
elixir-version: ${{matrix.elixir}} # Define the elixir version [required]
otp-version: ${{matrix.otp}} # Define the OTP version [required]
- name: Restore dependencies cache
uses: actions/cache@v2
with:
path: deps
key: ${{ runner.os }}-${{ matrix.elixir }}-${{ matrix.otp }}-mix-${{ hashFiles('**/mix.lock') }}
restore-keys: ${{ runner.os }}-${{ matrix.elixir }}-${{ matrix.otp }}-mix-
- name: Setup Postgres Database
run: docker compose up -d
- name: Install dependencies
run: mix deps.get
- name: Run tests
env:
MIX_ENV: test
run: mix do test.setup, test
12 changes: 12 additions & 0 deletions config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,15 @@ import Config

# Use Jason for JSON parsing in Phoenix
# config :phoenix, :json_library, Jason

config :kaffy, ecto_repos: [KaffyTest.Repo]

config :logger, level: :warning

config :kaffy, KaffyTest.Repo,
name: KaffyTest.Repo,
pool: Ecto.Adapters.SQL.Sandbox,
pool_size: System.schedulers_online() * 2,
priv: "test/support/postgres",
stacktrace: true,
url: "postgres://postgres:postgres@localhost:5432/kaffy_test"
11 changes: 11 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name: "kaffy"

services:
postgres:
image: postgres:16.2
ports:
- "5432:5432"
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: kaffy_test
20 changes: 18 additions & 2 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,16 @@ defmodule Kaffy.MixProject do
def project do
[
app: :kaffy,
aliases: aliases(),
version: @version,
elixir: "~> 1.12",
compilers: Mix.compilers(),
elixirc_paths: elixirc_paths(Mix.env()),
preferred_cli_env: [
"test.reset": :test,
"test.setup": :test,
"ecto.gen.migration": :test
],
start_permanent: Mix.env() == :prod,
description: description(),
package: package(),
Expand All @@ -29,20 +35,23 @@ defmodule Kaffy.MixProject do
end

# Specifies which paths to compile per environment.
defp elixirc_paths(:test), do: ["lib", "test/fixtures"]
defp elixirc_paths(:test), do: ["lib", "test/fixtures", "test/support"]
defp elixirc_paths(_), do: ["lib"]

# Run "mix help deps" to learn about dependencies.
defp deps do
[
{:ex_machina, "~> 2.7.0", only: :test},
{:phoenix, "~> 1.7.10"},
{:phoenix_html, "~> 4.0"},
{:phoenix_html_helpers, "~> 1.0"},
{:phoenix_view, "~> 2.0.2"},
{:mock, "~> 0.3.3", only: :test},
{:ecto, "~> 3.0"},
{:ecto_sql, "~> 3.10"},
{:ex_doc, ">= 0.0.0", only: :dev, runtime: false},
{:jason, "~> 1.3", only: :test}
{:jason, "~> 1.3", only: :test},
{:postgrex, "~> 0.16", optional: true}
]
end

Expand Down Expand Up @@ -77,4 +86,11 @@ defmodule Kaffy.MixProject do
formatters: ["html"]
]
end

defp aliases do
[
"test.reset": ["ecto.drop", "test.setup"],
"test.setup": ["ecto.create", "ecto.migrate"]
]
end
end
4 changes: 4 additions & 0 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
%{
"castore": {:hex, :castore, "1.0.5", "9eeebb394cc9a0f3ae56b813459f990abb0a3dedee1be6b27fdb50301930502f", [:mix], [], "hexpm", "8d7c597c3e4a64c395980882d4bca3cebb8d74197c590dc272cfd3b6a6310578"},
"db_connection": {:hex, :db_connection, "2.6.0", "77d835c472b5b67fc4f29556dee74bf511bbafecdcaf98c27d27fa5918152086", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c2f992d15725e721ec7fbc1189d4ecdb8afef76648c746a8e1cad35e3b8a35f3"},
"decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
"earmark_parser": {:hex, :earmark_parser, "1.4.33", "3c3fd9673bb5dcc9edc28dd90f50c87ce506d1f71b70e3de69aa8154bc695d44", [:mix], [], "hexpm", "2d526833729b59b9fdb85785078697c72ac5e5066350663e5be6a1182da61b8f"},
"ecto": {:hex, :ecto, "3.10.3", "eb2ae2eecd210b4eb8bece1217b297ad4ff824b4384c0e3fdd28aaf96edd6135", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "44bec74e2364d491d70f7e42cd0d690922659d329f6465e89feb8a34e8cd3433"},
"ecto_sql": {:hex, :ecto_sql, "3.10.2", "6b98b46534b5c2f8b8b5f03f126e75e2a73c64f3c071149d32987a5378b0fdbd", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.10.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "68c018debca57cb9235e3889affdaec7a10616a4e3a80c99fa1d01fdafaa9007"},
"ex_doc": {:hex, :ex_doc, "0.30.6", "5f8b54854b240a2b55c9734c4b1d0dd7bdd41f71a095d42a70445c03cf05a281", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "bd48f2ddacf4e482c727f9293d9498e0881597eae6ddc3d9562bd7923375109f"},
"ex_machina": {:hex, :ex_machina, "2.7.0", "b792cc3127fd0680fecdb6299235b4727a4944a09ff0fa904cc639272cd92dc7", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "419aa7a39bde11894c87a615c4ecaa52d8f107bbdd81d810465186f783245bf8"},
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
"makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"},
"makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"},
Expand All @@ -20,6 +23,7 @@
"phoenix_view": {:hex, :phoenix_view, "2.0.3", "4d32c4817fce933693741deeb99ef1392619f942633dde834a5163124813aad3", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "cd34049af41be2c627df99cd4eaa71fc52a328c0c3d8e7d4aa28f880c30e7f64"},
"plug": {:hex, :plug, "1.15.3", "712976f504418f6dff0a3e554c40d705a9bcf89a7ccef92fc6a5ef8f16a30a97", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "cc4365a3c010a56af402e0809208873d113e9c38c401cabd88027ef4f5c01fd2"},
"plug_crypto": {:hex, :plug_crypto, "2.0.0", "77515cc10af06645abbfb5e6ad7a3e9714f805ae118fa1a70205f80d2d70fe73", [:mix], [], "hexpm", "53695bae57cc4e54566d993eb01074e4d894b65a3766f1c43e2c61a1b0f45ea9"},
"postgrex": {:hex, :postgrex, "0.17.5", "0483d054938a8dc069b21bdd636bf56c487404c241ce6c319c1f43588246b281", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "50b8b11afbb2c4095a3ba675b4f055c416d0f3d7de6633a595fc131a828a67eb"},
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
"websock_adapter": {:hex, :websock_adapter, "0.5.5", "9dfeee8269b27e958a65b3e235b7e447769f66b5b5925385f5a569269164a210", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "4b977ba4a01918acbf77045ff88de7f6972c2a009213c515a445c48f224ffce9"},
Expand Down
6 changes: 5 additions & 1 deletion test/fixtures/travel_schema.ex
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ defmodule Fixtures.TravelSchema do
field(:description, :string)
field(:number_of_people, :integer)
field(:requires_passport, :boolean)
field(:travel_type, Ecto.Enum, values: [business: "business", leisure: "leisure", other: "undisclosed"])

field(:travel_type, Ecto.Enum,
values: [business: "business", leisure: "leisure", other: "undisclosed"]
)

field(:start_time, :utc_datetime)
field(:local_start_time, :naive_datetime)
field(:end_date, :date)
Expand Down
133 changes: 133 additions & 0 deletions test/kaffy/resource_query_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
defmodule Kaffy.ResourceQueryTest do
use Kaffy.DataCase, async: false

alias Kaffy.ResourceQuery
alias KaffyTest.Schemas.Pet

defmodule PetAdmin do
end

setup_all do
Application.put_env(:kaffy, :ecto_repo, KaffyTest.Repo)

Application.put_env(:kaffy, :resources, fn _ ->
[
admin: [
name: "Pets",
resources: [
pets: [
schema: KaffyTest.Schemas.Pet,
admin: PetAdmin
]
]
]
]
end)
end

setup do
conn =
build_conn()
|> Plug.Test.init_test_session(%{})
|> Phoenix.Controller.fetch_flash([])
|> Map.put(:query_params, %{})

[conn: conn]
end

describe "list_resource/3" do
test "returns all resources", %{conn: conn} do
[pet1 | _pets] = insert_list(3, :pet)
resource = Kaffy.Utils.get_resource(conn, "admin", "pets")
assert {3, pets} = ResourceQuery.list_resource(conn, resource, %{})
assert Enum.any?(pets, fn %Pet{} = pet -> pet.id == pet1.id end)
end

test "returns per_page limit", %{conn: conn} do
pets = insert_list(3, :pet)
resource = Kaffy.Utils.get_resource(conn, "admin", "pets")
assert {3, [returned_pet]} = ResourceQuery.list_resource(conn, resource, %{"limit" => "1"})

pet_ids = Enum.map(pets, & &1.id)
assert Enum.member?(pet_ids, returned_pet.id)
end

test "returns pages", %{conn: conn} do
pets = insert_list(3, :pet)

resource = Kaffy.Utils.get_resource(conn, "admin", "pets")

assert {3, [returned_pet1]} =
ResourceQuery.list_resource(conn, resource, %{"limit" => "1", "page" => "1"})

assert {3, [returned_pet2]} =
ResourceQuery.list_resource(conn, resource, %{"limit" => "1", "page" => "2"})

assert {3, [returned_pet3]} =
ResourceQuery.list_resource(conn, resource, %{"limit" => "1", "page" => "3"})

pet_ids =
Enum.map(pets, & &1.id)
|> Enum.sort()

returned_pet_ids =
[returned_pet1.id, returned_pet2.id, returned_pet3.id]
|> Enum.sort()

assert returned_pet_ids == pet_ids
end

test "returns search results", %{conn: conn} do
insert_list(3, :pet)
pet = insert(:pet, name: "Fido")
resource = Kaffy.Utils.get_resource(conn, "admin", "pets")

assert {1, [returned_pet]} =
ResourceQuery.list_resource(conn, resource, %{"search" => "Fido"})

assert returned_pet.id == pet.id
end

test "returns no results when search does not match", %{conn: conn} do
insert_list(3, :pet)
resource = Kaffy.Utils.get_resource(conn, "admin", "pets")
assert {0, []} = ResourceQuery.list_resource(conn, resource, %{"search" => "Fido"})
end

test "returns filter results", %{conn: conn} do
insert_list(3, :pet)
pet = insert(:pet, name: "Fido")
resource = Kaffy.Utils.get_resource(conn, "admin", "pets")
conn = Map.put(conn, :query_params, %{"person_id" => pet.person.id})
assert {1, [returned_pet]} = ResourceQuery.list_resource(conn, resource, %{})
assert returned_pet.id == pet.id
end

test "returns no results when filter does not match", %{conn: conn} do
insert_list(3, :pet)
resource = Kaffy.Utils.get_resource(conn, "admin", "pets")
conn = Map.put(conn, :query_params, %{"person_id" => "0"})
assert {0, []} = ResourceQuery.list_resource(conn, resource, %{})
end

test "returns ordered results", %{conn: conn} do
pets = insert_list(3, :pet)
resource = Kaffy.Utils.get_resource(conn, "admin", "pets")
conn = Map.put(conn, :query_params, %{"_of" => "id", "_ow" => "asc"})
assert {3, returned_pets} = ResourceQuery.list_resource(conn, resource, %{})
returned_pet_ids = Enum.map(returned_pets, & &1.id)
sorted_pet_ids = Enum.sort(Enum.map(pets, & &1.id))
assert returned_pet_ids == sorted_pet_ids
end

test "returns ordered results descending", %{conn: conn} do
pets = insert_list(3, :pet)
resource = Kaffy.Utils.get_resource(conn, "admin", "pets")
conn = Map.put(conn, :query_params, %{"_of" => "id", "_ow" => "desc"})
assert {3, returned_pets} = ResourceQuery.list_resource(conn, resource, %{})
returned_pet_ids = Enum.map(returned_pets, & &1.id)
sorted_pet_ids = Enum.reverse(Enum.sort(Enum.map(pets, & &1.id)))
assert returned_pet_ids == sorted_pet_ids
end
end
end
27 changes: 19 additions & 8 deletions test/resource_admin_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ defmodule Kaffy.ResourceAdminTest do
end

def deserialize_id(_schema, serialized_id) do
{person_id, pet_id} = serialized_id
|> Base.url_decode64!(padding: false)
|> :erlang.binary_to_term()
{person_id, pet_id} =
serialized_id
|> Base.url_decode64!(padding: false)
|> :erlang.binary_to_term()

[person_id: person_id, pet_id: pet_id]
end
Expand Down Expand Up @@ -75,11 +76,17 @@ defmodule Kaffy.ResourceAdminTest do
end

test "serialize composite id" do
assert ResourceAdmin.serialize_id([schema: Owner, admin: OwnerAdmin], %{person_id: 1, pet_id: 2}) == "1:2"
assert ResourceAdmin.serialize_id([schema: Owner, admin: OwnerAdmin], %{
person_id: 1,
pet_id: 2
}) == "1:2"
end

test "custom serialization of composite key" do
assert ResourceAdmin.serialize_id([schema: Owner, admin: OwnerETFAdmin], %{person_id: 1, pet_id: 2}) == "g2gCYQFhAg"
assert ResourceAdmin.serialize_id([schema: Owner, admin: OwnerETFAdmin], %{
person_id: 1,
pet_id: 2
}) == "g2gCYQFhAg"
end
end

Expand All @@ -89,14 +96,18 @@ defmodule Kaffy.ResourceAdminTest do
end

test "deserialize composite id" do
assert ResourceAdmin.deserialize_id([schema: Owner, admin: OwnerAdmin], "1:2") == [person_id: "1", pet_id: "2"]
assert ResourceAdmin.deserialize_id([schema: Owner, admin: OwnerAdmin], "1:2") == [
person_id: "1",
pet_id: "2"
]
end

test "custom deserialization of composite key" do
assert ResourceAdmin.deserialize_id([schema: Owner, admin: OwnerETFAdmin], "g2gCYQFhAg") == [person_id: 1, pet_id: 2]
assert ResourceAdmin.deserialize_id([schema: Owner, admin: OwnerETFAdmin], "g2gCYQFhAg") ==
[person_id: 1, pet_id: 2]
end
end

describe "index_description/1" do
test "nil if index_description is not defined as function in admin" do
refute ResourceAdmin.index_description(schema: Nested.Node, admin: NestedNodeAdmin)
Expand Down
Loading

0 comments on commit 88834e2

Please sign in to comment.