Skip to content

Commit

Permalink
Add initial auditing settings operations
Browse files Browse the repository at this point in the history
  • Loading branch information
nelsonkopliku committed Jun 12, 2024
1 parent 62c2b72 commit e9a101a
Show file tree
Hide file tree
Showing 3 changed files with 361 additions and 0 deletions.
79 changes: 79 additions & 0 deletions lib/trento/auditing.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
defmodule Trento.Auditing do
@moduledoc """
Auditing module
"""

require Logger

require Trento.Auditing.RetentionPeriodUnit, as: RetentionPeriodUnit

alias Trento.Auditing.Settings

alias Trento.Repo

@spec get_settings() ::
{:ok, Settings.t()} | {:error, :auditing_settings_not_configured}
def get_settings do
case Repo.one(Settings.base_query()) do
%Settings{} = settings -> {:ok, settings}
nil -> {:error, :auditing_settings_not_configured}
end
end

@spec save_retention_period(integer(), RetentionPeriodUnit.t()) ::
{:ok, Settings.t()} | {:error, :auditing_settings_already_configured}
def save_retention_period(retention_period, unit \\ RetentionPeriodUnit.days()) do
with {:ok, :auditing_settings_not_configured} <- ensure_no_settings_configured() do
nil
|> save_or_update_settings(retention_period, unit)
|> log_error("Error while saving auditing retention period")
end
end

@spec change_retention_period(integer(), RetentionPeriodUnit.t()) :: {:ok, Settings.t()}
def change_retention_period(retention_period, unit \\ RetentionPeriodUnit.days()) do
with {:ok, settings} <- get_settings() do
settings
|> save_or_update_settings(retention_period, unit)
|> log_error("Error while updating auditing retention period")
end
end

defp ensure_no_settings_configured do
case Repo.one(Settings.base_query()) do
nil ->
{:ok, :auditing_settings_not_configured}

%Settings{} ->
Logger.error("Error: Auditing settings already configured.")
{:error, :auditing_settings_already_configured}
end
end

defp save_or_update_settings(current_retention_period, retention_period, unit) do
case current_retention_period do
nil ->
%Settings{}
|> Settings.changeset(%{
retention_period: retention_period,
retention_period_unit: unit
})
|> Repo.insert()

%Settings{} ->
current_retention_period
|> Settings.changeset(%{
retention_period: retention_period,
retention_period_unit: unit
})
|> Repo.update()
end
end

defp log_error({:error, _} = error, message) do
Logger.error("#{message}: #{inspect(error)}")
error
end

defp log_error(result, _), do: result
end
11 changes: 11 additions & 0 deletions test/support/factory.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ defmodule Trento.Factory do
require Trento.Enums.Health, as: Health
require Trento.SoftwareUpdates.Enums.AdvisoryType, as: AdvisoryType
require Trento.SoftwareUpdates.Enums.SoftwareUpdatesHealth, as: SoftwareUpdatesHealth
require Trento.Auditing.RetentionPeriodUnit, as: RetentionPeriodUnit

alias Faker.Random.Elixir, as: RandomElixir

Expand Down Expand Up @@ -124,6 +125,8 @@ defmodule Trento.Factory do
InstallationSettings
}

alias Trento.Auditing.Settings, as: AuditingSettings

use ExMachina.Ecto, repo: Trento.Repo

def host_registered_event_factory do
Expand Down Expand Up @@ -932,4 +935,12 @@ defmodule Trento.Factory do
)
|> X509.Certificate.to_pem()
end

def auditing_settings_factory do
%AuditingSettings{
type: :auditing_settings,
retention_period: Enum.random(1..30),
retention_period_unit: Faker.Util.pick(RetentionPeriodUnit.values())
}
end
end
271 changes: 271 additions & 0 deletions test/trento/auditing_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
defmodule Trento.AuditingTest do
use ExUnit.Case
use Trento.DataCase

import Mox

import Trento.Factory

alias Trento.Auditing
alias Trento.Auditing.Settings

require Trento.Auditing.RetentionPeriodUnit, as: RetentionPeriodUnit

setup :verify_on_exit!

describe "retrieving auditing settings" do
test "should return an error when settings are not available" do
assert {:error, :auditing_settings_not_configured} == Auditing.get_settings()
end

test "should return settings" do
%{
retention_period: retention_period,
retention_period_unit: retention_period_unit
} = insert(:auditing_settings)

assert {:ok,
%Settings{
retention_period: ^retention_period,
retention_period_unit: ^retention_period_unit
}} = Auditing.get_settings()
end
end

@validation_scenarios [
%{
invalid_retention_periods: [-1, 0],
expected_errors: [
retention_period:
{"must be greater than %{number}",
[validation: :number, kind: :greater_than, number: 0]}
]
},
%{
invalid_retention_periods: [nil, "", " "],
expected_errors: [retention_period: {"can't be blank", [validation: :required]}]
}
]

describe "saving auditing settings" do
test "should not accept settings if previously saved" do
insert(:auditing_settings)

assert {:error, :auditing_settings_already_configured} =
Auditing.save_retention_period(42, RetentionPeriodUnit.weeks())
end

test "should not accept invalid retention periods" do
for %{
invalid_retention_periods: invalid_retention_periods,
expected_errors: expected_errors
} <- @validation_scenarios do
Enum.each(invalid_retention_periods, fn invalid_retention_period ->
retention_period_unit = Faker.Util.pick(RetentionPeriodUnit.values())

assert {:error,
%{
errors: ^expected_errors
}} =
Auditing.save_retention_period(invalid_retention_period, retention_period_unit)
end)
end
end

test "should not accept unsupported retention period units" do
for retention_period_unit <- [:foo, :bar, :baz] do
assert {:error,
%{
errors: [
retention_period_unit: {"is invalid", _}
]
}} = Auditing.save_retention_period(42, retention_period_unit)
end
end

scenarios = [
%{
name: "default retention period unit",
retention_period: 42,
expected_retention_period_unit: RetentionPeriodUnit.days()
},
%{
name: "days",
retention_period: 1,
retention_period_unit: RetentionPeriodUnit.days()
},
%{
name: "weeks",
retention_period: 3,
retention_period_unit: RetentionPeriodUnit.weeks()
},
%{
name: "months",
retention_period: 5,
retention_period_unit: RetentionPeriodUnit.months()
},
%{
name: "years",
retention_period: 7,
retention_period_unit: RetentionPeriodUnit.years()
}
]

for %{name: name} = scenario <- scenarios do
@scenario scenario

test "should save valid retention periods #{name}" do
%{retention_period: retention_period} = @scenario

expected_retention_period_unit =
Map.get(@scenario, :retention_period_unit, RetentionPeriodUnit.days())

case Map.has_key?(@scenario, :retention_period_unit) do
true ->
retention_period_unit = Map.fetch!(@scenario, :retention_period_unit)

assert {:ok,
%Settings{
retention_period: ^retention_period,
retention_period_unit: ^expected_retention_period_unit
}} =
Auditing.save_retention_period(retention_period, retention_period_unit)

false ->
assert {:ok,
%Settings{
retention_period: ^retention_period,
retention_period_unit: RetentionPeriodUnit.days()
}} =
Auditing.save_retention_period(retention_period)
end
end
end
end

describe "changing auditing settings" do
test "should not be able to change retention time if no auditing settings were previously saved" do
assert {:error, :auditing_settings_not_configured} ==
Auditing.change_retention_period(42, RetentionPeriodUnit.days())
end

test "should not accept invalid retention periods" do
insert(:auditing_settings)

for %{
invalid_retention_periods: invalid_retention_periods,
expected_errors: expected_errors
} <- @validation_scenarios do
Enum.each(invalid_retention_periods, fn invalid_retention_period ->
retention_period_unit = Faker.Util.pick(RetentionPeriodUnit.values())

assert {:error,
%{
errors: ^expected_errors
}} =
Auditing.change_retention_period(
invalid_retention_period,
retention_period_unit
)
end)
end
end

test "should not accept unsupported retention period units" do
insert(:auditing_settings)

for retention_period_unit <- [:foo, :bar, :baz] do
assert {:error,
%{
errors: [
retention_period_unit: {"is invalid", _}
]
}} = Auditing.change_retention_period(42, retention_period_unit)
end
end

scenarios = [
%{
name: "default retention period unit",
retention_period: 42,
expected_retention_period_unit: RetentionPeriodUnit.days()
},
%{
name: "days",
retention_period: 1,
retention_period_unit: RetentionPeriodUnit.days()
},
%{
name: "weeks",
retention_period: 3,
retention_period_unit: RetentionPeriodUnit.weeks()
},
%{
name: "months",
retention_period: 5,
retention_period_unit: RetentionPeriodUnit.months()
},
%{
name: "years",
retention_period: 7,
retention_period_unit: RetentionPeriodUnit.years()
}
]

for %{name: name} = scenario <- scenarios do
@scenario scenario

test "should successfully change retention periods #{name}" do
insert(:auditing_settings,
retention_period: 92,
retention_period_unit: RetentionPeriodUnit.years()
)

%{retention_period: retention_period} = @scenario

expected_retention_period_unit =
Map.get(@scenario, :retention_period_unit, RetentionPeriodUnit.days())

case Map.has_key?(@scenario, :retention_period_unit) do
true ->
retention_period_unit = Map.fetch!(@scenario, :retention_period_unit)

assert {:ok,
%Settings{
retention_period: ^retention_period,
retention_period_unit: ^expected_retention_period_unit
}} =
Auditing.change_retention_period(retention_period, retention_period_unit)

false ->
assert {:ok,
%Settings{
retention_period: ^retention_period,
retention_period_unit: RetentionPeriodUnit.days()
}} =
Auditing.change_retention_period(retention_period)
end
end
end

test "should successfully handle unchanging retention periods" do
initial_retention_period = 42
initial_retention_period_unit = RetentionPeriodUnit.days()

insert(:auditing_settings,
retention_period: initial_retention_period,
retention_period_unit: initial_retention_period_unit
)

assert {:ok,
%Settings{
retention_period: ^initial_retention_period,
retention_period_unit: ^initial_retention_period_unit
}} =
Auditing.change_retention_period(
initial_retention_period,
initial_retention_period_unit
)
end
end
end

0 comments on commit e9a101a

Please sign in to comment.