Skip to content

Commit

Permalink
Unit tests (#34)
Browse files Browse the repository at this point in the history
Adds unit tests for:
- `ErrorTracker`.
  - `report/3`
    - with a runtime exception
    - with a bad arithmetic error
    - with an unknown function error
    - with a throw
    - with an exit
  - `resolve/1`
  - `unresolve/1`
- `Telemetry`
  - verifies that events are emitted

Tests can run either on PostgreSQL or SQLite3. This is determined by the `DB` env var so:
- `DB=postgres mix test` runs the tests on PostgreSQL
- `DB=sqlite mix test` runs the tests on SQLite3

The CI has been also updated to run tests on both databases.

---

I've also unified the configuration under the `config/` folder. And the dev/test migrations under `priv/repo/`.

Previously we had some configuration in the root folder and other in `config/`. Regarding the migrations the `priv/repo/` folder is not included when publishing the package but is used in dev/test.
  • Loading branch information
crbelaus authored Aug 12, 2024
1 parent 0d8ae49 commit dd76462
Show file tree
Hide file tree
Showing 22 changed files with 345 additions and 125 deletions.
12 changes: 11 additions & 1 deletion .github/workflows/elixir.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Generate test configuration
run: cp config/test.example.exs config/test.exs

- uses: erlef/setup-beam@v1
with:
otp-version: ${{ matrix.erlang }}
Expand Down Expand Up @@ -71,5 +74,12 @@ jobs:
- name: Check Credo warnings
run: mix credo

- name: Run Tests
- name: Run Tests - SQLite3
run: mix test
env:
DB: sqlite

- name: Run Tests - PostgreSQL
run: mix test
env:
DB: postgres
12 changes: 9 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,14 @@ error_tracker-*.tar
# Temporary files, for example, from tests.
/tmp/

/assets/node_modules
# Configuration files (only the examples are committed)
/config/dev.exs
/config/test.exs

# Assets
/assets/node_modules

dev.local.exs
dev.db*
# SQLite3 databases
*.db
*.db-shm
*.db-wal
28 changes: 22 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,24 @@ Take a look at the [Getting Started](/guides/Getting%20Started.md) guide.

## Development

### Development server
### Initial setup and dependencies

We have a `dev.exs` script that starts a development server.
If this is the first time that you set up this project you will to generate the configuration files and adapt their content to your local environment:

To run it together with an `IEx` console you can do:
```
cp config/dev.example.exs config/dev.exs
cp config/test.example.exs config/test.exs
```

Then, you will need to download the dependencies:

```
iex -S mix dev
mix deps.get
```

### Assets

In order to participate in the development of this library, you may need to
know how to compile the assets needed to use the Web UI.
In order to participate in the development of this project, you may need to know how to compile the assets needed to use the Web UI.

To do so, you need to first make a clean build:

Expand All @@ -49,3 +53,15 @@ To do so you can execute this task in a separate terminal:
```
mix assets.watch
```



### Development server

We have a `dev.exs` script that starts a development server.

To run it together with an `IEx` console you can do:

```
iex -S mix dev
```
21 changes: 1 addition & 20 deletions config/config.exs
Original file line number Diff line number Diff line change
@@ -1,22 +1,3 @@
import Config

if config_env() == :dev do
config :tailwind,
version: "3.4.3",
default: [
args: ~w(
--config=tailwind.config.js
--input=css/app.css
--output=../priv/static/app.css
),
cd: Path.expand("../assets", __DIR__)
]

config :bun,
version: "1.1.18",
default: [
args: ~w(build app.js --outdir=../../priv/static),
cd: Path.expand("../assets/js", __DIR__),
env: %{}
]
end
import_config "#{config_env()}.exs"
40 changes: 40 additions & 0 deletions config/dev.example.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import Config

config :tailwind,
version: "3.4.3",
default: [
args: ~w(
--config=tailwind.config.js
--input=css/app.css
--output=../priv/static/app.css
),
cd: Path.expand("../assets", __DIR__)
]

config :bun,
version: "1.1.18",
default: [
args: ~w(build app.js --outdir=../../priv/static),
cd: Path.expand("../assets/js", __DIR__),
env: %{}
]

# PostgreSQL adapter
#
# To use SQLite3 on your local development machine uncomment these lines and
# comment the lines of other adapters.

config :error_tracker, :ecto_adapter, :postgres

config :error_tracker, ErrorTrackerDev.Repo,
url: "ecto://postgres:[email protected]/error_tracker_dev"

# SQLite3 adapter
#
# To use SQLite3 on your local development machine uncomment these lines and
# comment the lines of other adapters.

# config :error_tracker, :ecto_adapter, :sqlite3

# config :error_tracker, ErrorTrackerDev.Repo,
# database: System.get_env("SQLITE_DB") || "dev.db"
18 changes: 18 additions & 0 deletions config/test.example.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Config

config :error_tracker, ErrorTracker.Test.Repo,
url: "ecto://postgres:[email protected]/error_tracker_test",
pool: Ecto.Adapters.SQL.Sandbox,
log: false

config :error_tracker, ErrorTracker.Test.LiteRepo,
database: "priv/lite_repo/test.db",
pool: Ecto.Adapters.SQL.Sandbox,
log: false,
# Use the same migrations as the PostgreSQL repo
priv: "priv/repo"

config :error_tracker, ecto_repos: [ErrorTracker.Test.Repo]

# Repo is selected in the test_helper.exs based on the given ENV vars
config :error_tracker, otp_app: :error_tracker
17 changes: 3 additions & 14 deletions dev.exs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@
#######################################
Logger.configure(level: :debug)

# Get local configuration
Code.require_file("dev.local.exs")
# Get configuration
Config.Reader.read!("config/config.exs", env: :dev)

# Prepare the repo

adapter =
case Application.get_env(:error_tracker, :ecto_adapter) do
:postgres -> Ecto.Adapters.Postgres
Expand Down Expand Up @@ -173,13 +172,6 @@ defmodule ErrorTrackerDev.Telemetry do
end
end

defmodule Migration0 do
use Ecto.Migration

def up, do: ErrorTracker.Migration.up(prefix: "private")
def down, do: ErrorTracker.Migration.down(prefix: "private")
end

Application.put_env(:phoenix, :serve_endpoints, true)

Task.async(fn ->
Expand All @@ -194,10 +186,7 @@ Task.async(fn ->
{:ok, _} = Supervisor.start_link(children, strategy: :one_for_one)

# Automatically run the migrations on boot
Ecto.Migrator.run(ErrorTrackerDev.Repo, [{0, Migration0}], :up,
all: true,
log_migrations_sql: :debug
)
Ecto.Migrator.run(ErrorTrackerDev.Repo, :up, all: true, log_migrations_sql: :debug)

Process.sleep(:infinity)
end)
22 changes: 0 additions & 22 deletions dev.local.example.exs

This file was deleted.

7 changes: 1 addition & 6 deletions lib/error_tracker/integrations/oban.ex
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,7 @@ defmodule ErrorTracker.Integrations.Oban do
[:oban, :job, :exception]
]

@doc """
Attaches to Oban's Telemetry events if the library is detected.
This function is usually called internally during the startup process so you
don't have to.
"""
@doc false
def attach do
if Application.spec(:oban) do
:telemetry.attach_many(__MODULE__, @events, &__MODULE__.handle_event/4, :no_config)
Expand Down
7 changes: 1 addition & 6 deletions lib/error_tracker/integrations/phoenix.ex
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,7 @@ defmodule ErrorTracker.Integrations.Phoenix do
[:phoenix, :live_view, :render, :exception]
]

@doc """
Attaches to Phoenix's Telemetry events if the library is detected.
This function is usually called internally during the startup process so you
don't have to.
"""
@doc false
def attach do
if Application.spec(:phoenix) do
:telemetry.attach_many(__MODULE__, @events, &__MODULE__.handle_event/4, :no_config)
Expand Down
25 changes: 12 additions & 13 deletions lib/error_tracker/migration.ex
Original file line number Diff line number Diff line change
Expand Up @@ -61,35 +61,34 @@ defmodule ErrorTracker.Migration do
as "prefixes" in Ecto. With prefixes your error tables can reside outside of your primary
schema (which is usually named "public").
To use a prefix you need to specify it in your migrations:
To use a prefix you need to specify it in your configuration:
```elixir
defmodule MyApp.Repo.Migrations.AddErrorTracker do
use Ecto.Migration
def up, do: ErrorTracker.Migration.up(prefix: "custom_schema")
def down, do: ErrorTracker.Migration.down(prefix: "custom_schema")
end
config :error_tracker, :prefix, "custom_prefix"
```
This will automatically create the database schema for you. If the schema does already exist
Migrations will automatically create the database schema for you. If the schema does already exist
the migration may fail when trying to recreate it. In such cases you can instruct ErrorTracker
not to create the schema again:
```elixir
defmodule MyApp.Repo.Migrations.AddErrorTracker do
use Ecto.Migration
def up, do: ErrorTracker.Migration.up(prefix: "custom_schema", create_schema: false)
def down, do: ErrorTracker.Migration.down(prefix: "custom_schema")
def up, do: ErrorTracker.Migration.up(create_schema: false)
def down, do: ErrorTracker.Migration.down()
end
```
If you are using a custom schema other than the default "public" you need to configure
ErrorTracker to use that schema:
You can also override the configured prefix in the migration:
```elixir
config :error_tracker, :prefix, "custom_schema"
defmodule MyApp.Repo.Migrations.AddErrorTracker do
use Ecto.Migration
def up, do: ErrorTracker.Migration.up(prefix: "custom_prefix")
def down, do: ErrorTracker.Migration.down(prefix: "custom_prefix")
end
```
"""

Expand Down
3 changes: 2 additions & 1 deletion lib/error_tracker/migration/postgres.ex
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ defmodule ErrorTracker.Migration.Postgres do
end

defp with_defaults(opts, version) do
opts = Enum.into(opts, %{prefix: @default_prefix, version: version})
configured_prefix = Application.get_env(:error_tracker, :prefix, "public")
opts = Enum.into(opts, %{prefix: configured_prefix, version: version})

opts
|> Map.put_new(:create_schema, opts.prefix != @default_prefix)
Expand Down
4 changes: 3 additions & 1 deletion lib/error_tracker/migration/sql_migrator.ex
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,13 @@ defmodule ErrorTracker.Migration.SQLMigrator do

defp record_version(_opts, 0), do: :ok

defp record_version(%{prefix: prefix}, version) do
defp record_version(opts, version) do
timestamp = DateTime.utc_now() |> DateTime.to_unix()

case repo().__adapter__() do
Ecto.Adapters.Postgres ->
prefix = opts[:prefix]

execute """
INSERT INTO #{prefix}.error_tracker_meta (key, value)
VALUES ('migration_version', '#{version}'), ('migration_timestamp', #{timestamp})
Expand Down
1 change: 0 additions & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ defmodule ErrorTracker.MixProject do

defp aliases do
[
setup: ["deps.get", "cmd --cd assets npm install"],
dev: "run --no-halt dev.exs",
"assets.install": ["bun.install", "cmd _build/bun install --cwd assets/"],
"assets.watch": ["tailwind default --watch"],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
defmodule ErrorTracker.Repo.Migrations.CreateErrorTrackerTables do
use Ecto.Migration

defdelegate up, to: ErrorTracker.Migration
defdelegate down, to: ErrorTracker.Migration
end
45 changes: 45 additions & 0 deletions test/error_tracker/telemetry_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
defmodule ErrorTracker.TelemetryTest do
use ErrorTracker.Test.Case

alias ErrorTracker.Error
alias ErrorTracker.Occurrence

setup do
attach_telemetry()

:ok
end

test "event is emitted for new errors" do
# Since the error is new, both the new error and new occurrence events will be emitted
report_error(fn -> raise "This is a test" end)
assert_receive {:telemetry_event, [:error_tracker, :error, :new], _, %{error: %Error{}}}

assert_receive {:telemetry_event, [:error_tracker, :occurrence, :new], _,
%{occurrence: %Occurrence{}}}

# The error is already known so the new error event won't be emitted
report_error(fn -> raise "This is a test" end)

refute_receive {:telemetry_event, [:error_tracker, :error, :new], _,
%{occurrence: %Occurrence{}}},
150

assert_receive {:telemetry_event, [:error_tracker, :occurrence, :new], _,
%{occurrence: %Occurrence{}}}
end

test "event is emitted for resolved and unresolved errors" do
%Occurrence{error: error = %Error{}} = report_error(fn -> raise "This is a test" end)

# The resolved event will be emitted
{:ok, resolved = %Error{}} = ErrorTracker.resolve(error)
assert_receive {:telemetry_event, [:error_tracker, :error, :resolved], _, %{error: %Error{}}}

# The unresolved event will be emitted
{:ok, _unresolved} = ErrorTracker.unresolve(resolved)

assert_receive {:telemetry_event, [:error_tracker, :error, :unresolved], _,
%{error: %Error{}}}
end
end
Loading

0 comments on commit dd76462

Please sign in to comment.