From 0a8812aa06d54c9b4e6fb12f3378a4294729c3d2 Mon Sep 17 00:00:00 2001 From: Zack Siri Date: Mon, 24 Jun 2024 16:23:20 +0700 Subject: [PATCH] Add test for transitioning assessments --- lib/polar/machines/assessment.ex | 20 ++++- lib/polar/machines/assessment/event.ex | 12 +++ lib/polar/machines/assessment/transit.ex | 17 ++++ lib/polar/machines/assessment/transitions.ex | 24 ++++++ ...0240624084728_create_assessment_events.exs | 28 +++++++ .../machines/assessment/manager_test.exs | 56 +++++++++++++ .../machines/assessment/transitions_test.exs | 79 +++++++++++++++++++ 7 files changed, 233 insertions(+), 3 deletions(-) create mode 100644 lib/polar/machines/assessment/event.ex create mode 100644 lib/polar/machines/assessment/transit.ex create mode 100644 lib/polar/machines/assessment/transitions.ex create mode 100644 priv/repo/migrations/20240624084728_create_assessment_events.exs create mode 100644 test/polar/machines/assessment/manager_test.exs create mode 100644 test/polar/machines/assessment/transitions_test.exs diff --git a/lib/polar/machines/assessment.ex b/lib/polar/machines/assessment.ex index c44b481..760ff83 100644 --- a/lib/polar/machines/assessment.ex +++ b/lib/polar/machines/assessment.ex @@ -6,14 +6,28 @@ defmodule Polar.Machines.Assessment do alias Polar.Machines.Check alias Polar.Machines.Cluster - @valid_attrs ~w(version_id cluster_id check_slug)a - @required_attrs ~w(version_id cluster_id check_slug)a + alias __MODULE__.Event + alias __MODULE__.Transitions + + use Eventful.Transitable + + Transitions + |> governs(:current_state, on: Event) + + @valid_attrs ~w( + version_id + cluster_id + )a + + @required_attrs ~w( + version_id + cluster_id + )a schema "assessments" do field :current_state, :string, default: "created" field :check_slug, :string, virtual: true - belongs_to :check, Check belongs_to :cluster, Cluster diff --git a/lib/polar/machines/assessment/event.ex b/lib/polar/machines/assessment/event.ex new file mode 100644 index 0000000..8d192a6 --- /dev/null +++ b/lib/polar/machines/assessment/event.ex @@ -0,0 +1,12 @@ +defmodule Polar.Machines.Assessment.Event do + alias Polar.Machines.Assessment + alias Polar.Accounts.User + + use Eventful, + parent: {:assessment, Assessment}, + actor: {:user, User} + + alias Assessment.Transitions + + handle(:transitions, using: Transitions) +end diff --git a/lib/polar/machines/assessment/transit.ex b/lib/polar/machines/assessment/transit.ex new file mode 100644 index 0000000..6afe34d --- /dev/null +++ b/lib/polar/machines/assessment/transit.ex @@ -0,0 +1,17 @@ +defimpl Eventful.Transit, for: Polar.Machines.Assessment do + alias Polar.Machines.Assessment.Event + + def perform(assessment, user, event_name, options \\ []) do + comment = Keyword.get(options, :comment) + domain = Keyword.get(options, :domain, "transitions") + parameters = Keyword.get(options, :parameters, %{}) + + assessment + |> Event.handle(user, %{ + domain: domain, + name: event_name, + comment: comment, + parameters: parameters + }) + end +end diff --git a/lib/polar/machines/assessment/transitions.ex b/lib/polar/machines/assessment/transitions.ex new file mode 100644 index 0000000..0bed85e --- /dev/null +++ b/lib/polar/machines/assessment/transitions.ex @@ -0,0 +1,24 @@ +defmodule Polar.Machines.Assessment.Transitions do + @behaviour Eventful.Handler + use Eventful.Transition, repo: Polar.Repo + + alias Polar.Machines.Assessment + + Assessment + |> transition( + [from: "created", to: "running", via: "run"], + fn changes -> transit(changes) end + ) + + Assessment + |> transition( + [from: "running", to: "passed", via: "pass"], + fn changes -> transit(changes) end + ) + + Assessment + |> transition( + [from: "running", to: "failed", via: "fail"], + fn changes -> transit(changes) end + ) +end diff --git a/priv/repo/migrations/20240624084728_create_assessment_events.exs b/priv/repo/migrations/20240624084728_create_assessment_events.exs new file mode 100644 index 0000000..c69e4a1 --- /dev/null +++ b/priv/repo/migrations/20240624084728_create_assessment_events.exs @@ -0,0 +1,28 @@ +defmodule Polar.Repo.Migrations.CreateAssessmentEvents do + use Ecto.Migration + + def change do + create table(:assessment_events) do + add(:name, :citext, null: false) + add(:domain, :citext, null: false) + add(:metadata, :map, default: "{}") + + add( + :assessment_id, + references(:assessments, on_delete: :restrict), + null: false + ) + + add( + :user_id, + references(:users, on_delete: :restrict), + null: false + ) + + timestamps(type: :utc_datetime_usec) + end + + create index(:assessment_events, [:assessment_id]) + create index(:assessment_events, [:user_id]) + end +end diff --git a/test/polar/machines/assessment/manager_test.exs b/test/polar/machines/assessment/manager_test.exs new file mode 100644 index 0000000..0803032 --- /dev/null +++ b/test/polar/machines/assessment/manager_test.exs @@ -0,0 +1,56 @@ +defmodule Polar.Machines.Assessment.ManagerTest do + use Polar.DataCase, async: true + + alias Polar.Machines + alias Polar.Streams + + import Polar.StreamsFixtures + + setup do + {:ok, check} = + Machines.create_check(%{ + name: "ipv4-issuing", + description: "issue ipv4 correctly" + }) + + {:ok, cluster} = + Machines.create_cluster(%{ + name: "example", + type: "lxd", + arch: "amd64", + credential_endpoint: "some.cluster.com:8443", + credential_password: "sometoken", + credential_password_confirmation: "sometoken" + }) + + {:ok, product} = + Streams.create_product(%{ + aliases: ["alpine/3.19", "alpine/3.19/default"], + arch: "amd64", + os: "Alpine", + release: "3.19", + release_title: "3.19", + variant: "default", + requirements: %{ + secureboot: "false" + } + }) + + {:ok, version} = + Streams.create_version(product, valid_version_attributes(2)) + + {:ok, check: check, cluster: cluster, version: version} + end + + describe "create assessment" do + test "successfully create assessment", %{check: check, cluster: cluster, version: version} do + assert {:ok, assessment} = + Machines.create_assessment(check, %{ + version_id: version.id, + cluster_id: cluster.id + }) + + assert assessment.current_state == "created" + end + end +end diff --git a/test/polar/machines/assessment/transitions_test.exs b/test/polar/machines/assessment/transitions_test.exs new file mode 100644 index 0000000..30fc4c6 --- /dev/null +++ b/test/polar/machines/assessment/transitions_test.exs @@ -0,0 +1,79 @@ +defmodule Polar.Machines.Assessment.TransitionsTest do + use Polar.DataCase, async: true + + alias Polar.Machines + alias Polar.Streams + + import Polar.StreamsFixtures + import Polar.AccountsFixtures + + setup do + user = user_fixture() + + {:ok, check} = + Machines.create_check(%{ + name: "ipv4-issuing", + description: "issue ipv4 correctly" + }) + + {:ok, cluster} = + Machines.create_cluster(%{ + name: "example", + type: "lxd", + arch: "amd64", + credential_endpoint: "some.cluster.com:8443", + credential_password: "sometoken", + credential_password_confirmation: "sometoken" + }) + + {:ok, product} = + Streams.create_product(%{ + aliases: ["alpine/3.19", "alpine/3.19/default"], + arch: "amd64", + os: "Alpine", + release: "3.19", + release_title: "3.19", + variant: "default", + requirements: %{ + secureboot: "false" + } + }) + + {:ok, version} = + Streams.create_version(product, valid_version_attributes(2)) + + {:ok, assessment} = + Machines.create_assessment(check, %{ + version_id: version.id, + cluster_id: cluster.id + }) + + {:ok, assessment: assessment, user: user} + end + + describe "transitions" do + test "run", %{assessment: assessment, user: user} do + assert {:ok, %{resource: resource}} = Eventful.Transit.perform(assessment, user, "run") + + assert resource.current_state == "running" + end + + test "pass", %{assessment: assessment, user: user} do + {:ok, %{resource: running_assessment}} = Eventful.Transit.perform(assessment, user, "run") + + assert {:ok, %{resource: resource}} = + Eventful.Transit.perform(running_assessment, user, "pass") + + assert resource.current_state == "passed" + end + + test "fail", %{assessment: assessment, user: user} do + {:ok, %{resource: running_assessment}} = Eventful.Transit.perform(assessment, user, "run") + + assert {:ok, %{resource: resource}} = + Eventful.Transit.perform(running_assessment, user, "fail") + + assert resource.current_state == "failed" + end + end +end