diff --git a/lib/polar/machines.ex b/lib/polar/machines.ex index 303fe5b..1e2ef74 100644 --- a/lib/polar/machines.ex +++ b/lib/polar/machines.ex @@ -21,7 +21,7 @@ defmodule Polar.Machines do alias __MODULE__.Assessment - defdelegate create_assessment(version, params), + defdelegate get_or_create_assessment(version, params), to: Assessment.Manager, - as: :create + as: :get_or_create end diff --git a/lib/polar/machines/assessment.ex b/lib/polar/machines/assessment.ex index 48a4fb0..a896bda 100644 --- a/lib/polar/machines/assessment.ex +++ b/lib/polar/machines/assessment.ex @@ -17,16 +17,20 @@ defmodule Polar.Machines.Assessment do @valid_attrs ~w( check_id cluster_id + instance_type )a @required_attrs ~w( check_id cluster_id + instance_type )a schema "assessments" do field :current_state, :string, default: "created" + field :instance_type, :string + belongs_to :check, Check belongs_to :cluster, Cluster @@ -40,5 +44,6 @@ defmodule Polar.Machines.Assessment do assessment |> cast(attrs, @valid_attrs) |> validate_required(@required_attrs) + |> validate_inclusion(:instance_type, ["container", "vm"]) end end diff --git a/lib/polar/machines/assessment/manager.ex b/lib/polar/machines/assessment/manager.ex index 621f840..e46e548 100644 --- a/lib/polar/machines/assessment/manager.ex +++ b/lib/polar/machines/assessment/manager.ex @@ -2,6 +2,25 @@ defmodule Polar.Machines.Assessment.Manager do alias Polar.Repo alias Polar.Machines.Assessment + def get_or_create(version, params) do + check_id = Map.get(params, "check_id") || params.check_id + instance_type = Map.get(params, "instance_type") || params.instance_type + + Assessment + |> Repo.get_by( + version_id: version.id, + check_id: check_id, + instance_type: instance_type + ) + |> case do + %Assessment{} = assessment -> + assessment + + nil -> + create(version, params) + end + end + def create(version, params) do %Assessment{version_id: version.id} |> Assessment.changeset(params) diff --git a/lib/polar/machines/assessment/transitions.ex b/lib/polar/machines/assessment/transitions.ex index 0bed85e..8775338 100644 --- a/lib/polar/machines/assessment/transitions.ex +++ b/lib/polar/machines/assessment/transitions.ex @@ -10,6 +10,18 @@ defmodule Polar.Machines.Assessment.Transitions do fn changes -> transit(changes) end ) + Assessment + |> transition( + [from: "failed", to: "running", via: "run"], + fn changes -> transit(changes) end + ) + + Assessment + |> transition( + [from: "running", to: "running", via: "run"], + fn changes -> transit(changes) end + ) + Assessment |> transition( [from: "running", to: "passed", via: "pass"], diff --git a/lib/polar/streams/version/transitions.ex b/lib/polar/streams/version/transitions.ex index 1aa8ef9..2b79322 100644 --- a/lib/polar/streams/version/transitions.ex +++ b/lib/polar/streams/version/transitions.ex @@ -10,6 +10,12 @@ defmodule Polar.Streams.Version.Transitions do fn changes -> transit(changes) end ) + Version + |> transition( + [from: "inactive", to: "testing", via: "test"], + fn changes -> transit(changes) end + ) + Version |> transition( [from: "testing", to: "inactive", via: "deactivate"], diff --git a/lib/polar_web/controllers/publish/testing/assessment_controller.ex b/lib/polar_web/controllers/publish/testing/assessment_controller.ex index 27694e1..8067ed6 100644 --- a/lib/polar_web/controllers/publish/testing/assessment_controller.ex +++ b/lib/polar_web/controllers/publish/testing/assessment_controller.ex @@ -6,16 +6,21 @@ defmodule PolarWeb.Publish.Testing.AssessmentController do alias Polar.Streams.Version + alias PolarWeb.Params.Assessment + + action_fallback PolarWeb.FallbackController + def create(conn, %{ "version_id" => version_id, "assessment" => assessment_params }) do with %Version{} = check <- Repo.get(Version, version_id), - {:ok, assessment} <- Machines.create_assessment(check, assessment_params) do + {:ok, assessment_params} <- Assessment.parse(assessment_params), + {:ok, assessment} <- + Machines.get_or_create_assessment(check, Map.from_struct(assessment_params)) do assessment = Repo.preload(assessment, [:check]) conn - |> put_status(:created) |> render(:create, %{assessment: assessment}) end end diff --git a/lib/polar_web/controllers/publish/testing/check_controller.ex b/lib/polar_web/controllers/publish/testing/check_controller.ex index 7707ca8..6218756 100644 --- a/lib/polar_web/controllers/publish/testing/check_controller.ex +++ b/lib/polar_web/controllers/publish/testing/check_controller.ex @@ -3,6 +3,8 @@ defmodule PolarWeb.Publish.Testing.CheckController do alias Polar.Machines + action_fallback PolarWeb.FallbackController + def index(conn, _params) do checks = Machines.list_checks() diff --git a/lib/polar_web/controllers/publish/testing/cluster_controller.ex b/lib/polar_web/controllers/publish/testing/cluster_controller.ex index c191370..1851fd4 100644 --- a/lib/polar_web/controllers/publish/testing/cluster_controller.ex +++ b/lib/polar_web/controllers/publish/testing/cluster_controller.ex @@ -3,6 +3,8 @@ defmodule PolarWeb.Publish.Testing.ClusterController do alias Polar.Machines + action_fallback PolarWeb.FallbackController + def index(conn, _params) do clusters = Machines.list_clusters(:for_testing) diff --git a/lib/polar_web/controllers/publish/testing/cluster_json.ex b/lib/polar_web/controllers/publish/testing/cluster_json.ex index 0cea9c9..016d847 100644 --- a/lib/polar_web/controllers/publish/testing/cluster_json.ex +++ b/lib/polar_web/controllers/publish/testing/cluster_json.ex @@ -10,6 +10,8 @@ defmodule PolarWeb.Publish.Testing.ClusterJSON do def data(%Cluster{} = cluster) do %{ id: cluster.id, + type: cluster.type, + arch: cluster.arch, credential: cluster.credential, current_state: cluster.current_state } diff --git a/lib/polar_web/controllers/publish/version_controller.ex b/lib/polar_web/controllers/publish/version_controller.ex index 69cafe2..59f5ca6 100644 --- a/lib/polar_web/controllers/publish/version_controller.ex +++ b/lib/polar_web/controllers/publish/version_controller.ex @@ -4,9 +4,18 @@ defmodule PolarWeb.Publish.VersionController do alias Polar.Repo alias Polar.Streams alias Polar.Streams.Product + alias Polar.Streams.Version action_fallback PolarWeb.FallbackController + def show(conn, %{"product_id" => product_id, "id" => serial}) do + version = Repo.get_by(Version, product_id: product_id, serial: serial) + + if version do + render(conn, :show, %{version: version}) + end + end + def create(conn, %{"product_id" => product_id, "version" => version_params}) do product = Repo.get(Product, product_id) diff --git a/lib/polar_web/controllers/publish/version_json.ex b/lib/polar_web/controllers/publish/version_json.ex index 73b07fc..937c014 100644 --- a/lib/polar_web/controllers/publish/version_json.ex +++ b/lib/polar_web/controllers/publish/version_json.ex @@ -1,4 +1,8 @@ defmodule PolarWeb.Publish.VersionJSON do + def show(%{version: version}) do + %{data: %{id: version.id}} + end + def create(%{version: version}) do %{data: %{id: version.id}} end diff --git a/lib/polar_web/params/assessment.ex b/lib/polar_web/params/assessment.ex new file mode 100644 index 0000000..d5b84e9 --- /dev/null +++ b/lib/polar_web/params/assessment.ex @@ -0,0 +1,29 @@ +defmodule PolarWeb.Params.Assessment do + use Ecto.Schema + import Ecto.Changeset + + @required_attrs ~w( + check_id + cluster_id + instance_type + )a + + @primary_key false + embedded_schema do + field :check_id, :integer + field :cluster_id, :integer + field :instance_type, :string + end + + def parse(params) do + %__MODULE__{} + |> changeset(params) + |> apply_action(:insert) + end + + def changeset(assessment, params) do + assessment + |> cast(params, @required_attrs) + |> validate_required(@required_attrs) + end +end diff --git a/lib/polar_web/router.ex b/lib/polar_web/router.ex index 81ce85f..72e710b 100644 --- a/lib/polar_web/router.ex +++ b/lib/polar_web/router.ex @@ -102,7 +102,7 @@ defmodule PolarWeb.Router do resources "/storage", StorageController, only: [:show], singleton: true resources "/products", ProductController, only: [:show] do - resources "/versions", VersionController, only: [:create] + resources "/versions", VersionController, only: [:show, :create] end resources "/versions/:version_id/events", EventController, only: [:create] diff --git a/priv/repo/migrations/20240628092615_add_instance_type_to_assessments.exs b/priv/repo/migrations/20240628092615_add_instance_type_to_assessments.exs new file mode 100644 index 0000000..dada87b --- /dev/null +++ b/priv/repo/migrations/20240628092615_add_instance_type_to_assessments.exs @@ -0,0 +1,12 @@ +defmodule Polar.Repo.Migrations.AddInstanceTypeToAssessments do + use Ecto.Migration + + def change do + alter table(:assessments) do + add :instance_type, :string, null: false + end + + drop index(:assessments, [:check_id, :version_id], unique: true) + create index(:assessments, [:check_id, :version_id, :instance_type], unique: true) + end +end diff --git a/test/polar/machines/assessment/manager_test.exs b/test/polar/machines/assessment/manager_test.exs index c6f872d..a38ed69 100644 --- a/test/polar/machines/assessment/manager_test.exs +++ b/test/polar/machines/assessment/manager_test.exs @@ -45,9 +45,10 @@ defmodule Polar.Machines.Assessment.ManagerTest do describe "create assessment" do test "successfully create assessment", %{check: check, cluster: cluster, version: version} do assert {:ok, assessment} = - Machines.create_assessment(version, %{ + Machines.get_or_create_assessment(version, %{ check_id: check.id, - cluster_id: cluster.id + cluster_id: cluster.id, + instance_type: "container" }) assert assessment.current_state == "created" diff --git a/test/polar/machines/assessment/transitions_test.exs b/test/polar/machines/assessment/transitions_test.exs index 8dc081f..830998f 100644 --- a/test/polar/machines/assessment/transitions_test.exs +++ b/test/polar/machines/assessment/transitions_test.exs @@ -43,9 +43,10 @@ defmodule Polar.Machines.Assessment.TransitionsTest do Streams.create_version(product, valid_version_attributes(2)) {:ok, assessment} = - Machines.create_assessment(version, %{ + Machines.get_or_create_assessment(version, %{ check_id: check.id, - cluster_id: cluster.id + cluster_id: cluster.id, + instance_type: "container" }) {:ok, assessment: assessment, user: user} diff --git a/test/polar_web/controllers/publish/event_controller_test.exs b/test/polar_web/controllers/publish/event_controller_test.exs index 8e1c440..3f17d83 100644 --- a/test/polar_web/controllers/publish/event_controller_test.exs +++ b/test/polar_web/controllers/publish/event_controller_test.exs @@ -68,7 +68,11 @@ defmodule PolarWeb.Publish.EventControllerTest do }) {:ok, assessment} = - Machines.create_assessment(version, %{check_id: check.id, cluster_id: cluster.id}) + Machines.get_or_create_assessment(version, %{ + check_id: check.id, + cluster_id: cluster.id, + instance_type: "container" + }) {:ok, assessment: assessment} end diff --git a/test/polar_web/controllers/publish/testing/assessment_controller_test.exs b/test/polar_web/controllers/publish/testing/assessment_controller_test.exs index eb412a8..4bdddf0 100644 --- a/test/polar_web/controllers/publish/testing/assessment_controller_test.exs +++ b/test/polar_web/controllers/publish/testing/assessment_controller_test.exs @@ -69,13 +69,31 @@ defmodule PolarWeb.Publish.Testing.AssessmentControllerTest do post(conn, ~p"/publish/testing/versions/#{version.id}/assessments", %{ "assessment" => %{ "check_id" => check.id, - "cluster_id" => cluster.id + "cluster_id" => cluster.id, + "instance_type" => "container" } }) - assert %{"data" => data} = json_response(conn, 201) + assert %{"data" => data} = json_response(conn, 200) assert %{"id" => _id, "current_state" => "created", "check" => _check} = data end + + test "invalid parameter passed in", %{ + version: version, + conn: conn, + check: check, + cluster: cluster + } do + conn = + post(conn, ~p"/publish/testing/versions/#{version.id}/assessments", %{ + "assessment" => %{ + "check_id" => check.id, + "cluster_id" => cluster.id + } + }) + + assert %{"errors" => _errors} = json_response(conn, 422) + end end end diff --git a/test/polar_web/controllers/publish/version_controller_test.exs b/test/polar_web/controllers/publish/version_controller_test.exs index dbb237a..f598d12 100644 --- a/test/polar_web/controllers/publish/version_controller_test.exs +++ b/test/polar_web/controllers/publish/version_controller_test.exs @@ -7,6 +7,8 @@ defmodule PolarWeb.Publish.VersionControllerTest do alias Polar.Accounts alias Polar.Streams + import Polar.StreamsFixtures + setup do password = Accounts.generate_automation_password() @@ -25,6 +27,27 @@ defmodule PolarWeb.Publish.VersionControllerTest do {:ok, conn: conn} end + describe "GET /publish/products/:product_id/versions/:id" do + setup do + product_attributes = valid_product_attributes("alpine:3.19:amd64:default") + + {:ok, product} = Streams.create_product(product_attributes) + + {:ok, version} = + Streams.create_version(product, valid_version_attributes(2)) + + {:ok, product: product, version: version} + end + + test "can fetch existing version", %{conn: conn, product: product, version: version} do + conn = get(conn, "/publish/products/#{product.id}/versions/#{version.serial}") + + assert %{"data" => data} = json_response(conn, 200) + + assert %{"id" => _id} = data + end + end + describe "POST /publish/products/:product_id/versions" do setup do product_attributes = valid_product_attributes("alpine:3.19:amd64:default")