diff --git a/lib/nerves_hub/managed_deployments.ex b/lib/nerves_hub/managed_deployments.ex index ea6fa7955..d44b12853 100644 --- a/lib/nerves_hub/managed_deployments.ex +++ b/lib/nerves_hub/managed_deployments.ex @@ -3,6 +3,7 @@ defmodule NervesHub.ManagedDeployments do require Logger + alias NervesHub.Accounts.User alias NervesHub.AuditLogs.DeploymentGroupTemplates alias NervesHub.AuditLogs.DeviceTemplates alias NervesHub.Devices @@ -11,6 +12,7 @@ defmodule NervesHub.ManagedDeployments do alias NervesHub.Firmwares alias NervesHub.Firmwares.FirmwareDelta alias NervesHub.ManagedDeployments.DeploymentGroup + alias NervesHub.ManagedDeployments.DeploymentRelease alias NervesHub.ManagedDeployments.Distributed.Orchestrator, as: DistributedOrchestrator alias NervesHub.Products.Product alias Phoenix.Channel.Server, as: PhoenixChannelServer @@ -193,27 +195,31 @@ defmodule NervesHub.ManagedDeployments do Update a deployment - Records audit logs depending on changes + - Creates deployment release record if firmware_id or archive_id changed """ - @spec update_deployment_group(DeploymentGroup.t(), map) :: + @spec update_deployment_group(DeploymentGroup.t(), map, User.t()) :: {:ok, DeploymentGroup.t()} | {:error, Changeset.t()} - def update_deployment_group(deployment_group, params) do + def update_deployment_group(deployment_group, params, user) do + deployment_group = Repo.preload(deployment_group, :firmware) + result = - Repo.transaction(fn -> + Repo.transact(fn -> changeset = deployment_group - |> Repo.preload(:firmware) |> DeploymentGroup.update_changeset(params) - case Repo.update(changeset) do - {:ok, deployment_group} -> - deployment_group = Repo.preload(deployment_group, [:firmware], force: true) - - audit_changes!(deployment_group, changeset) - - {deployment_group, changeset} - - {:error, changeset} -> - Repo.rollback(changeset) + create_deployment_release? = + Map.has_key?(changeset.changes, :firmware_id) or + Map.has_key?(changeset.changes, :archive_id) + + with {:ok, deployment_group} <- Repo.update(changeset), + :ok <- create_audit_logs!(deployment_group, changeset), + {:ok, _deployment_group} <- + if(create_deployment_release?, + do: create_deployment_release(deployment_group, user.id), + else: {:ok, nil} + ) do + {:ok, {deployment_group, changeset}} end end) @@ -237,7 +243,18 @@ defmodule NervesHub.ManagedDeployments do end end - defp audit_changes!(deployment_group, changeset) do + defp create_deployment_release(deployment_group, user_id) do + %DeploymentRelease{} + |> DeploymentRelease.changeset(%{ + deployment_group_id: deployment_group.id, + firmware_id: deployment_group.firmware_id, + archive_id: deployment_group.archive_id, + created_by_id: user_id + }) + |> Repo.insert() + end + + defp create_audit_logs!(deployment_group, changeset) do Enum.each(changeset.changes, fn {:archive_id, archive_id} -> # Trigger the new archive to get downloaded by devices @@ -330,11 +347,17 @@ defmodule NervesHub.ManagedDeployments do Ecto.Changeset.change(%DeploymentGroup{}) end - @spec create_deployment_group(map(), Product.t()) :: + @spec create_deployment_group(map(), Product.t(), User.t()) :: {:ok, DeploymentGroup.t()} | {:error, Changeset.t()} - def create_deployment_group(params, %Product{} = product) do - DeploymentGroup.create_changeset(params, product) - |> Repo.insert() + def create_deployment_group(params, %Product{} = product, user) do + Repo.transact(fn -> + changeset = DeploymentGroup.create_changeset(params, product) + + with {:ok, deployment_group} <- Repo.insert(changeset), + {:ok, _release} <- create_deployment_release(deployment_group, user.id) do + {:ok, deployment_group} + end + end) |> case do {:ok, deployment_group} -> deployment_created_event(deployment_group) @@ -346,6 +369,21 @@ defmodule NervesHub.ManagedDeployments do end end + @doc """ + List all deployment releases for a deployment group, ordered by most recent first. + """ + @spec list_deployment_releases(DeploymentGroup.t()) :: [DeploymentRelease.t()] + def list_deployment_releases(%DeploymentGroup{id: deployment_group_id}) do + DeploymentRelease + |> where([r], r.deployment_group_id == ^deployment_group_id) + |> join(:inner, [r], f in assoc(r, :firmware)) + |> join(:inner, [r], u in assoc(r, :user)) + |> join(:left, [r], a in assoc(r, :archive)) + |> preload([r, f, u, a], firmware: f, user: u, archive: a) + |> order_by([r], desc: r.inserted_at, desc: r.id) + |> Repo.all() + end + @spec broadcast(DeploymentGroup.t() | atom(), String.t(), map()) :: :ok | {:error, term()} def broadcast(deployment_group, event, payload \\ %{}) diff --git a/lib/nerves_hub/managed_deployments/deployment_group.ex b/lib/nerves_hub/managed_deployments/deployment_group.ex index 395535592..a3f4734c8 100644 --- a/lib/nerves_hub/managed_deployments/deployment_group.ex +++ b/lib/nerves_hub/managed_deployments/deployment_group.ex @@ -38,7 +38,7 @@ defmodule NervesHub.ManagedDeployments.DeploymentGroup do has_many(:inflight_updates, InflightUpdate, foreign_key: :deployment_id) has_many(:devices, Device, foreign_key: :deployment_id, on_delete: :nilify_all) - has_many(:deployment_releases, DeploymentRelease) + has_many(:deployment_releases, DeploymentRelease, on_delete: :delete_all) has_many(:update_stats, UpdateStat, on_delete: :nilify_all, foreign_key: :deployment_id) embeds_one :conditions, __MODULE__.Conditions, primary_key: false, on_replace: :update do diff --git a/lib/nerves_hub/managed_deployments/deployment_release.ex b/lib/nerves_hub/managed_deployments/deployment_release.ex index 0d96f11be..d99cdb451 100644 --- a/lib/nerves_hub/managed_deployments/deployment_release.ex +++ b/lib/nerves_hub/managed_deployments/deployment_release.ex @@ -15,9 +15,7 @@ defmodule NervesHub.ManagedDeployments.DeploymentRelease do @required_fields [ :deployment_group_id, :firmware_id, - :archive_id, - :created_by_id, - :status + :created_by_id ] @optional_fields [:archive_id] diff --git a/lib/nerves_hub_web/components/deployment_group_page/release_history.ex b/lib/nerves_hub_web/components/deployment_group_page/release_history.ex index 2f5eb084f..56901486b 100644 --- a/lib/nerves_hub_web/components/deployment_group_page/release_history.ex +++ b/lib/nerves_hub_web/components/deployment_group_page/release_history.ex @@ -9,9 +9,61 @@ defmodule NervesHubWeb.Components.DeploymentGroupPage.ReleaseHistory do def render(assigns) do ~H""" -
-
- Coming Soon... +
+
+
+
+
Release History
+
+ +
+
No releases yet
+
+ Release history will appear here when you change the firmware version in settings. +
+
+ +
+ + + + + + + + + + + + + + + + + + + +
ReleasedFirmware VersionUUIDArchiveReleased By
+
+ {Calendar.strftime(release.inserted_at, "%B %d, %Y")} + {Calendar.strftime(release.inserted_at, "%I:%M %p")} UTC +
+
+ {release.firmware.version} + + {release.firmware.uuid} + + + {release.archive.version} ({String.slice(release.archive.uuid, 0..7)}) + + + None + + + {release.user.name} +
+
+
""" diff --git a/lib/nerves_hub_web/components/deployment_group_page/settings.ex b/lib/nerves_hub_web/components/deployment_group_page/settings.ex index d577f27a8..99b53e2db 100644 --- a/lib/nerves_hub_web/components/deployment_group_page/settings.ex +++ b/lib/nerves_hub_web/components/deployment_group_page/settings.ex @@ -286,7 +286,7 @@ defmodule NervesHubWeb.Components.DeploymentGroupPage.Settings do authorized!(:"deployment_group:update", org_user) - case ManagedDeployments.update_deployment_group(deployment_group, params) do + case ManagedDeployments.update_deployment_group(deployment_group, params, user) do {:ok, updated} -> # Use original deployment so changes will get # marked in audit log diff --git a/lib/nerves_hub_web/controllers/api/deployment_group_controller.ex b/lib/nerves_hub_web/controllers/api/deployment_group_controller.ex index 5d78e5dcd..5d9247a6a 100644 --- a/lib/nerves_hub_web/controllers/api/deployment_group_controller.ex +++ b/lib/nerves_hub_web/controllers/api/deployment_group_controller.ex @@ -29,7 +29,7 @@ defmodule NervesHubWeb.API.DeploymentGroupController do uuid -> with {:ok, firmware} <- Firmwares.get_firmware_by_product_and_uuid(product, uuid), params = Map.put(params, "firmware_id", firmware.id), - {:ok, deployment_group} <- ManagedDeployments.create_deployment_group(params, product) do + {:ok, deployment_group} <- ManagedDeployments.create_deployment_group(params, product, user) do DeploymentGroupTemplates.audit_deployment_created(user, deployment_group) conn @@ -67,7 +67,7 @@ defmodule NervesHubWeb.API.DeploymentGroupController do ManagedDeployments.get_deployment_group_by_name(product, name), params = update_params(product, deployment_group_params), {:ok, updated_deployment_group} <- - ManagedDeployments.update_deployment_group(deployment_group, params) do + ManagedDeployments.update_deployment_group(deployment_group, params, user) do DeploymentGroupTemplates.audit_deployment_updated(user, deployment_group) render(conn, :show, deployment_group: updated_deployment_group) diff --git a/lib/nerves_hub_web/live/deployment_groups/new.ex b/lib/nerves_hub_web/live/deployment_groups/new.ex index 919eb05d0..3497583a4 100644 --- a/lib/nerves_hub_web/live/deployment_groups/new.ex +++ b/lib/nerves_hub_web/live/deployment_groups/new.ex @@ -143,7 +143,7 @@ defmodule NervesHubWeb.Live.DeploymentGroups.New do %{user: user, org: org, product: product} = socket.assigns - ManagedDeployments.create_deployment_group(params, product) + ManagedDeployments.create_deployment_group(params, product, user) |> case do {:ok, deployment_group} -> _ = DeploymentGroupTemplates.audit_deployment_created(user, deployment_group) diff --git a/lib/nerves_hub_web/live/deployment_groups/show.ex b/lib/nerves_hub_web/live/deployment_groups/show.ex index 6689005d0..eb0c03b2f 100644 --- a/lib/nerves_hub_web/live/deployment_groups/show.ex +++ b/lib/nerves_hub_web/live/deployment_groups/show.ex @@ -38,6 +38,7 @@ defmodule NervesHubWeb.Live.DeploymentGroups.Show do inflight_updates = Devices.inflight_updates_for(deployment_group) updating_count = Devices.updating_count(deployment_group) + releases = ManagedDeployments.list_deployment_releases(deployment_group) :ok = socket.endpoint.subscribe("deployment:#{deployment_group.id}:internal") @@ -55,6 +56,7 @@ defmodule NervesHubWeb.Live.DeploymentGroups.Show do |> assign(:firmware, deployment_group.firmware) |> assign(:deltas, Firmwares.get_deltas_by_target_firmware(deployment_group.firmware)) |> assign(:update_stats, UpdateStats.stats_by_deployment(deployment_group)) + |> assign(:releases, releases) |> assign_matched_devices_count() |> schedule_inflight_updates_updater() |> ok() @@ -85,7 +87,7 @@ defmodule NervesHubWeb.Live.DeploymentGroups.Show do value = !deployment_group.is_active {:ok, deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{is_active: value}) + ManagedDeployments.update_deployment_group(deployment_group, %{is_active: value}, user) active_str = if value, do: "active", else: "inactive" DeploymentGroupTemplates.audit_deployment_toggle_active(user, deployment_group, active_str) diff --git a/lib/nerves_hub_web/live/deployment_groups/show.html.heex b/lib/nerves_hub_web/live/deployment_groups/show.html.heex index 0a44489da..c08609349 100644 --- a/lib/nerves_hub_web/live/deployment_groups/show.html.heex +++ b/lib/nerves_hub_web/live/deployment_groups/show.html.heex @@ -101,7 +101,7 @@ update_stats={@update_stats} /> - <.live_component :if={@tab == :release_history} module={ReleaseHistoryTab} id="deployment_group_release_history" /> + <.live_component :if={@tab == :release_history} module={ReleaseHistoryTab} id="deployment_group_release_history" releases={@releases} /> <.live_component :if={@tab == :activity} module={ActivityTab} id="deployment_group_activity" deployment_group={@deployment_group} org={@org} product={@product} user={@user} /> diff --git a/priv/repo/migrations/20251206184125_add_cascade_delete_to_deployment_releases.exs b/priv/repo/migrations/20251206184125_add_cascade_delete_to_deployment_releases.exs new file mode 100644 index 000000000..d01a24fcf --- /dev/null +++ b/priv/repo/migrations/20251206184125_add_cascade_delete_to_deployment_releases.exs @@ -0,0 +1,23 @@ +defmodule NervesHub.Repo.Migrations.AddCascadeDeleteToDeploymentReleases do + use Ecto.Migration + + def up do + # Drop the existing foreign key constraint + drop constraint(:deployment_releases, "deployment_releases_deployment_group_id_fkey") + + # Add it back with cascade delete + alter table(:deployment_releases) do + modify :deployment_group_id, references(:deployments, on_delete: :delete_all), null: false + end + end + + def down do + # Drop the cascade delete foreign key constraint + drop constraint(:deployment_releases, "deployment_releases_deployment_group_id_fkey") + + # Add it back without cascade delete (original state) + alter table(:deployment_releases) do + modify :deployment_group_id, references(:deployments), null: false + end + end +end diff --git a/test/nerves_hub/devices/update_stats_test.exs b/test/nerves_hub/devices/update_stats_test.exs index d1584aa5f..dab497699 100644 --- a/test/nerves_hub/devices/update_stats_test.exs +++ b/test/nerves_hub/devices/update_stats_test.exs @@ -183,7 +183,8 @@ defmodule NervesHub.Devices.UpdateStatsTest do source_firmware: source_firmware, target_firmware: target_firmware, other_firmware: other_firmware, - source_firmware_metadata: source_firmware_metadata + source_firmware_metadata: source_firmware_metadata, + user: user } do device = Devices.update_deployment_group(device, deployment_group) device2 = Devices.update_deployment_group(device2, deployment_group) @@ -193,9 +194,13 @@ defmodule NervesHub.Devices.UpdateStatsTest do :ok = UpdateStats.log_update(device, source_firmware_metadata) {:ok, deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{ - firmware_id: other_firmware.id - }) + ManagedDeployments.update_deployment_group( + deployment_group, + %{ + firmware_id: other_firmware.id + }, + user + ) # deployment group needs to be explicitly passed in because association # is already preloaded from fixtures, causing the preload in log_update/2 diff --git a/test/nerves_hub/devices_test.exs b/test/nerves_hub/devices_test.exs index 7ff2c1bd2..8a18fb8aa 100644 --- a/test/nerves_hub/devices_test.exs +++ b/test/nerves_hub/devices_test.exs @@ -805,12 +805,17 @@ defmodule NervesHub.DevicesTest do deployment_group: deployment_group, device: device1 = %{id: device1_id}, org: org, - product: product + product: product, + user: user } do {:ok, deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{ - enable_priority_updates: true - }) + ManagedDeployments.update_deployment_group( + deployment_group, + %{ + enable_priority_updates: true + }, + user + ) {:ok, device1} = Devices.update_device(device1, %{first_seen_at: DateTime.utc_now()}) diff --git a/test/nerves_hub/managed_deployments/distributed/orchestrator_test.exs b/test/nerves_hub/managed_deployments/distributed/orchestrator_test.exs index e120c2153..f6b62b93a 100644 --- a/test/nerves_hub/managed_deployments/distributed/orchestrator_test.exs +++ b/test/nerves_hub/managed_deployments/distributed/orchestrator_test.exs @@ -51,16 +51,21 @@ defmodule NervesHub.ManagedDeployments.Distributed.OrchestratorTest do org_key: org_key, device: device1, device2: device2, - device3: device3 + device3: device3, + user: user } do # setup deployment group, listen for broadcasts, and start the orchestrator firmware = Fixtures.firmware_fixture(org_key, product) {:ok, deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{ - concurrent_updates: 2, - firmware_id: firmware.id - }) + ManagedDeployments.update_deployment_group( + deployment_group, + %{ + concurrent_updates: 2, + firmware_id: firmware.id + }, + user + ) {:ok, _pid} = start_supervised(%{ @@ -114,11 +119,12 @@ defmodule NervesHub.ManagedDeployments.Distributed.OrchestratorTest do deployment_group: deployment_group, org_key: org_key, device: device, - device2: device2 + device2: device2, + user: user } do # only allow for 1 update at a time {:ok, deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{concurrent_updates: 1}) + ManagedDeployments.update_deployment_group(deployment_group, %{concurrent_updates: 1}, user) device = Devices.update_deployment_group(device, deployment_group) {:ok, connection} = Connections.device_connecting(device, device.product_id) @@ -148,7 +154,7 @@ defmodule NervesHub.ManagedDeployments.Distributed.OrchestratorTest do firmware = Fixtures.firmware_fixture(org_key, product) {:ok, _deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{firmware_id: firmware.id}) + ManagedDeployments.update_deployment_group(deployment_group, %{firmware_id: firmware.id}, user) # check that the first device was told to update assert_receive %Broadcast{topic: ^topic1, event: "update"}, 500 @@ -183,11 +189,12 @@ defmodule NervesHub.ManagedDeployments.Distributed.OrchestratorTest do product: product, deployment_group: deployment_group, org_key: org_key, - device: device + device: device, + user: user } do # only allow for 1 update at a time {:ok, deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{concurrent_updates: 1}) + ManagedDeployments.update_deployment_group(deployment_group, %{concurrent_updates: 1}, user) device = Devices.update_deployment_group(device, deployment_group) {:ok, device} = Devices.update_device(device, %{firmware_validation_status: "not_validated"}) @@ -211,7 +218,7 @@ defmodule NervesHub.ManagedDeployments.Distributed.OrchestratorTest do firmware = Fixtures.firmware_fixture(org_key, product) {:ok, _deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{firmware_id: firmware.id}) + ManagedDeployments.update_deployment_group(deployment_group, %{firmware_id: firmware.id}, user) # check that the device is not told to update refute_receive %Broadcast{topic: ^topic1, event: "update"}, 1_000 @@ -222,7 +229,8 @@ defmodule NervesHub.ManagedDeployments.Distributed.OrchestratorTest do org_key: org_key, product: product, device: device1, - device2: device2 + device2: device2, + user: user } do # An ugly set of expectations # `Devices.available_for_update` should be called: @@ -241,10 +249,14 @@ defmodule NervesHub.ManagedDeployments.Distributed.OrchestratorTest do firmware = Fixtures.firmware_fixture(org_key, product) {:ok, deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{ - concurrent_updates: 2, - firmware_id: firmware.id - }) + ManagedDeployments.update_deployment_group( + deployment_group, + %{ + concurrent_updates: 2, + firmware_id: firmware.id + }, + user + ) deployment_group_topic = "orchestrator:deployment:#{deployment_group.id}" Phoenix.PubSub.subscribe(NervesHub.PubSub, deployment_group_topic) @@ -316,10 +328,14 @@ defmodule NervesHub.ManagedDeployments.Distributed.OrchestratorTest do firmware = Fixtures.firmware_fixture(org_key, product) {:ok, deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{ - concurrent_updates: 2, - firmware_id: firmware.id - }) + ManagedDeployments.update_deployment_group( + deployment_group, + %{ + concurrent_updates: 2, + firmware_id: firmware.id + }, + user + ) deployment_topic = "orchestrator:deployment:#{deployment_group.id}" Phoenix.PubSub.subscribe(NervesHub.PubSub, deployment_topic) @@ -441,7 +457,8 @@ defmodule NervesHub.ManagedDeployments.Distributed.OrchestratorTest do test "handles delta subscriptions when firmware changes", %{ deployment_group: deployment_group, org_key: org_key, - product: product + product: product, + user: user } do new_firmware = %{id: new_firmware_id} = Fixtures.firmware_fixture(org_key, product) %{firmware_id: old_firmware_id} = deployment_group @@ -458,7 +475,7 @@ defmodule NervesHub.ManagedDeployments.Distributed.OrchestratorTest do expect(Firmwares, :unsubscribe_firmware_delta_target, fn ^old_firmware_id -> :ok end) expect(Firmwares, :subscribe_firmware_delta_target, fn ^new_firmware_id -> :ok end) - {:ok, _} = ManagedDeployments.update_deployment_group(deployment_group, %{firmware_id: new_firmware.id}) + {:ok, _} = ManagedDeployments.update_deployment_group(deployment_group, %{firmware_id: new_firmware.id}, user) _ = :sys.get_state(pid) end @@ -466,7 +483,8 @@ defmodule NervesHub.ManagedDeployments.Distributed.OrchestratorTest do deployment_group: deployment_group, org_key: org_key, product: product, - org: org + org: org, + user: user } do other_firmware = Fixtures.firmware_fixture(org_key, product) @@ -491,7 +509,7 @@ defmodule NervesHub.ManagedDeployments.Distributed.OrchestratorTest do allow(Devices, self(), pid) - {:ok, _} = ManagedDeployments.update_deployment_group(deployment_group, %{is_active: true}) + {:ok, _} = ManagedDeployments.update_deployment_group(deployment_group, %{is_active: true}, user) _ = :sys.get_state(pid) end diff --git a/test/nerves_hub/managed_deployments_test.exs b/test/nerves_hub/managed_deployments_test.exs index 1b33ca76d..7286b53be 100644 --- a/test/nerves_hub/managed_deployments_test.exs +++ b/test/nerves_hub/managed_deployments_test.exs @@ -33,6 +33,7 @@ defmodule NervesHub.ManagedDeploymentsTest do {:ok, %{ + user: user, org: org, org_key: org_key, firmware: firmware, @@ -48,7 +49,8 @@ defmodule NervesHub.ManagedDeploymentsTest do describe "create deployment" do test "create_deployment_group with valid parameters", %{ product: product, - firmware: firmware + firmware: firmware, + user: user } do params = %{ name: "a different name", @@ -60,7 +62,7 @@ defmodule NervesHub.ManagedDeploymentsTest do } {:ok, %DeploymentGroup{} = deployment_group} = - ManagedDeployments.create_deployment_group(params, product) + ManagedDeployments.create_deployment_group(params, product, user) for key <- Map.keys(params) do case Map.get(deployment_group, key) do @@ -76,7 +78,8 @@ defmodule NervesHub.ManagedDeploymentsTest do test "deployments have unique names wrt product", %{ firmware: firmware, product: product, - deployment_group: existing_deployment_group + deployment_group: existing_deployment_group, + user: user } do params = %{ name: existing_deployment_group.name, @@ -88,10 +91,10 @@ defmodule NervesHub.ManagedDeploymentsTest do } assert {:error, %Ecto.Changeset{errors: [name: {"has already been taken", _}]}} = - ManagedDeployments.create_deployment_group(params, product) + ManagedDeployments.create_deployment_group(params, product, user) end - test "create_deployment_group with invalid parameters", %{product: product, firmware: firmware} do + test "create_deployment_group with invalid parameters fails", %{product: product, firmware: firmware, user: user} do params = %{ name: "", conditions: %{ @@ -101,10 +104,10 @@ defmodule NervesHub.ManagedDeploymentsTest do firmware_id: firmware.id } - assert {:error, %Changeset{}} = ManagedDeployments.create_deployment_group(params, product) + assert {:error, %Changeset{}} = ManagedDeployments.create_deployment_group(params, product, user) end - test "create_deployment_group with non existant firmware", %{product: product} do + test "create_deployment_group with non existant firmware fails", %{product: product, user: user} do params = %{ name: "Boop", conditions: %{ @@ -115,10 +118,10 @@ defmodule NervesHub.ManagedDeploymentsTest do } assert {:error, %Changeset{errors: [firmware_id: {"does not exist", _}]}} = - ManagedDeployments.create_deployment_group(params, product) + ManagedDeployments.create_deployment_group(params, product, user) end - test "create_deployment_group with non existant (empty) firmware", %{product: product} do + test "create_deployment_group with non existant (empty) firmware fails", %{product: product, user: user} do params = %{ name: "Boop", conditions: %{ @@ -134,12 +137,42 @@ defmodule NervesHub.ManagedDeploymentsTest do {:firmware_id, {"can't be blank", [validation: :required]}} ] }} = - ManagedDeployments.create_deployment_group(params, product) + ManagedDeployments.create_deployment_group(params, product, user) + end + + test "creates release history when deployment group is created with firmware", %{ + product: product, + firmware: firmware, + user: user + } do + params = %{ + name: "new deployment with release", + conditions: %{ + version: "< 1.0.0", + tags: ["beta"] + }, + firmware_id: firmware.id + } + + {:ok, deployment_group} = ManagedDeployments.create_deployment_group(params, product, user) + + releases = ManagedDeployments.list_deployment_releases(deployment_group) + + assert length(releases) == 1 + [release] = releases + + assert release.deployment_group_id == deployment_group.id + assert release.firmware_id == firmware.id + refute release.archive_id + assert release.created_by_id == user.id + assert release.firmware.id == firmware.id + assert release.user.id == user.id end end - describe "update_deployment_group/2" do + describe "update_deployment_group/3" do test "updating firmware sends an update message", %{ + user: user, org_key: org_key, firmware: firmware, product: product @@ -157,18 +190,19 @@ defmodule NervesHub.ManagedDeploymentsTest do firmware_id: firmware.id } - {:ok, deployment_group} = ManagedDeployments.create_deployment_group(params, product) + {:ok, deployment_group} = ManagedDeployments.create_deployment_group(params, product, user) Phoenix.PubSub.subscribe(NervesHub.PubSub, "deployment:#{deployment_group.id}") {:ok, _deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{is_active: true}) + ManagedDeployments.update_deployment_group(deployment_group, %{is_active: true}, user) assert_broadcast("deployments/update", %{}, 500) end test "starts distributed orchestrator if deployment updates to active from inactive", %{ + user: user, deployment_group: deployment_group } do refute deployment_group.is_active @@ -186,10 +220,10 @@ defmodule NervesHub.ManagedDeploymentsTest do ) {:ok, deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{is_active: true}) + ManagedDeployments.update_deployment_group(deployment_group, %{is_active: true}, user) {:ok, _deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{is_active: false}) + ManagedDeployments.update_deployment_group(deployment_group, %{is_active: false}, user) topic = "orchestrator:deployment:#{deployment_group.id}" assert_receive %Broadcast{topic: ^topic, event: "deactivated"}, 500 @@ -197,6 +231,7 @@ defmodule NervesHub.ManagedDeploymentsTest do test "triggers delta generation when firmware is updated and delta updates are enabled", %{ + user: user, deployment_group: deployment_group, firmware: firmware, org: org, @@ -204,7 +239,7 @@ defmodule NervesHub.ManagedDeploymentsTest do product: product } do {:ok, deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: true}) + ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: true}, user) assert deployment_group.delta_updatable assert deployment_group.firmware_id == firmware.id @@ -218,13 +253,14 @@ defmodule NervesHub.ManagedDeploymentsTest do new_firmware = Fixtures.firmware_fixture(org_key, product) {:ok, _deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{firmware_id: new_firmware.id}) + ManagedDeployments.update_deployment_group(deployment_group, %{firmware_id: new_firmware.id}, user) assert_enqueued(worker: FirmwareDeltaBuilder, args: %{source_id: firmware.id, target_id: new_firmware.id}) end test "triggers delta generation when delta updates are enabled", %{ + user: user, deployment_group: deployment_group, firmware: firmware, org: org, @@ -237,7 +273,7 @@ defmodule NervesHub.ManagedDeploymentsTest do new_firmware = Fixtures.firmware_fixture(org_key, product) {:ok, deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{firmware_id: new_firmware.id}) + ManagedDeployments.update_deployment_group(deployment_group, %{firmware_id: new_firmware.id}, user) device = Fixtures.device_fixture(org, product, firmware, %{tags: ["beta", "rpi"]}) @@ -246,13 +282,14 @@ defmodule NervesHub.ManagedDeploymentsTest do assert device.deployment_id == deployment_group.id {:ok, _deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: true}) + ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: true}, user) assert_enqueued(worker: FirmwareDeltaBuilder, args: %{source_id: firmware.id, target_id: new_firmware.id}) end test "does not trigger delta generation if firmware has not changed", %{ + user: user, deployment_group: deployment_group, firmware: firmware, org: org, @@ -268,13 +305,14 @@ defmodule NervesHub.ManagedDeploymentsTest do assert device.deployment_id == deployment_group.id {:ok, _deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: true}) + ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: true}, user) reject(FirmwareDeltaBuilder, :new, 1) end test "triggers delta generation for every unique device firmware + deployment firmware combination", %{ + user: user, deployment_group: deployment_group, firmware: firmware, org: org, @@ -306,31 +344,142 @@ defmodule NervesHub.ManagedDeploymentsTest do |> Devices.update_deployment_group(deployment_group) {:ok, _deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: true}) + ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: true}, user) assert_enqueued(worker: FirmwareDeltaBuilder, args: %{source_id: firmware2.id, target_id: firmware.id}) assert_enqueued(worker: FirmwareDeltaBuilder, args: %{source_id: firmware3.id, target_id: firmware.id}) assert_enqueued(worker: FirmwareDeltaBuilder, args: %{source_id: firmware4.id, target_id: firmware.id}) end - test "sets status to :preparing when turning on deltas", %{deployment_group: deployment_group} do + test "sets status to :preparing when turning on deltas", %{user: user, deployment_group: deployment_group} do assert deployment_group.status == :ready {:ok, deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: true}) + ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: true}, user) assert deployment_group.status == :preparing end - test "sets status to :ready when turning off deltas", %{deployment_group: deployment_group} do + test "sets status to :ready when turning off deltas", %{user: user, deployment_group: deployment_group} do {:ok, deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: true}) + ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: true}, user) {:ok, deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: false}) + ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: false}, user) assert deployment_group.status == :ready end + + test "creates release record when either firmware or archive change", %{ + user: user, + deployment_group: deployment_group, + org_key: org_key, + product: product + } do + # One from the initial creation + assert length(ManagedDeployments.list_deployment_releases(deployment_group)) == 1 + + new_firmware = Fixtures.firmware_fixture(org_key, product, %{version: "3.0.0"}) + archive = Fixtures.archive_fixture(org_key, product, %{version: "1.0.0"}) + + {:ok, updated_deployment_group} = + ManagedDeployments.update_deployment_group( + deployment_group, + %{firmware_id: new_firmware.id, archive_id: archive.id}, + user + ) + + releases = ManagedDeployments.list_deployment_releases(updated_deployment_group) + assert length(releases) == 2 + + [release | _rest] = releases + assert release.firmware_id == new_firmware.id + assert release.archive_id == archive.id + assert release.archive.version == "1.0.0" + + {:ok, updated_deployment_group} = + ManagedDeployments.update_deployment_group( + updated_deployment_group, + %{archive_id: nil}, + user + ) + + releases = ManagedDeployments.list_deployment_releases(updated_deployment_group) + assert length(releases) == 3 + [latest_release | _rest] = releases + assert latest_release.archive_id == nil + end + + test "does not create release record when firmware is not changed", %{ + user: user, + deployment_group: deployment_group + } do + releases = ManagedDeployments.list_deployment_releases(deployment_group) + assert length(releases) == 1 + # Update something other than firmware + {:ok, _updated_deployment_group} = + ManagedDeployments.update_deployment_group( + deployment_group, + %{is_active: true}, + user + ) + + # Should have no new releases + assert ManagedDeployments.list_deployment_releases(deployment_group) == releases + end + + test "list_deployment_releases returns releases ordered by most recent first", %{ + user: user, + deployment_group: deployment_group, + org_key: org_key, + product: product + } do + # Create several new releases + Enum.each(["2.0.0", "2.1.0", "2.2.0"], fn version -> + firmware = Fixtures.firmware_fixture(org_key, product, %{version: version}) + + {:ok, updated_dg} = + ManagedDeployments.update_deployment_group( + deployment_group, + %{firmware_id: firmware.id}, + user + ) + + updated_dg + end) + + releases = ManagedDeployments.list_deployment_releases(deployment_group) + # 4 because one is created when the deployment group is created + assert length(releases) == 4 + + assert Enum.map(releases, & &1.firmware.version) == ["2.2.0", "2.1.0", "2.0.0", deployment_group.firmware.version] + end + + test "deployment releases are cascade deleted when deployment group is deleted", %{ + user: user, + deployment_group: deployment_group, + org_key: org_key, + product: product + } do + # Create some releases + firmware1 = Fixtures.firmware_fixture(org_key, product, %{version: "2.0.0"}) + firmware2 = Fixtures.firmware_fixture(org_key, product, %{version: "2.1.0"}) + + {:ok, deployment_group} = + ManagedDeployments.update_deployment_group(deployment_group, %{firmware_id: firmware1.id}, user) + + {:ok, deployment_group} = + ManagedDeployments.update_deployment_group(deployment_group, %{firmware_id: firmware2.id}, user) + + releases = ManagedDeployments.list_deployment_releases(deployment_group) + assert length(releases) == 3 + + # Delete the deployment group + {:ok, _deleted} = ManagedDeployments.delete_deployment_group(deployment_group) + + # Verify releases are deleted + assert ManagedDeployments.list_deployment_releases(deployment_group) == [] + end end describe "devices matching deployments" do @@ -661,7 +810,7 @@ defmodule NervesHub.ManagedDeploymentsTest do end describe "matched_devices_count/2" do - setup %{org: org, product: product, firmware: firmware} = + setup %{org: org, product: product, firmware: firmware, user: user} = context do {:ok, deployment_group} = ManagedDeployments.create_deployment_group( @@ -673,7 +822,8 @@ defmodule NervesHub.ManagedDeploymentsTest do }, firmware_id: firmware.id }, - product + product, + user ) Fixtures.device_fixture(org, product, firmware, %{ @@ -701,28 +851,39 @@ defmodule NervesHub.ManagedDeploymentsTest do end test "counts devices for deployment group with tags but no version", %{ + user: user, deployment_group: deployment_group } do {:ok, deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{ - conditions: %{"tags" => ["beta", "rpi"], "version" => ""} - }) + ManagedDeployments.update_deployment_group( + deployment_group, + %{ + conditions: %{"tags" => ["beta", "rpi"], "version" => ""} + }, + user + ) assert ManagedDeployments.matched_devices_count(deployment_group, in_deployment: true) == 2 end test "counts devices for deployment group with tags and version", %{ + user: user, deployment_group: deployment_group } do {:ok, deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{ - conditions: %{"tags" => ["beta", "rpi"], "version" => "> 1.1.0"} - }) + ManagedDeployments.update_deployment_group( + deployment_group, + %{ + conditions: %{"tags" => ["beta", "rpi"], "version" => "> 1.1.0"} + }, + user + ) assert ManagedDeployments.matched_devices_count(deployment_group, in_deployment: true) == 1 end test "accounts for devices outside of deployment group", %{ + user: user, deployment_group: deployment_group, org: org, product: product, @@ -736,14 +897,19 @@ defmodule NervesHub.ManagedDeploymentsTest do refute device.deployment_id {:ok, deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{ - conditions: %{"tags" => ["beta", "rpi"], "version" => ""} - }) + ManagedDeployments.update_deployment_group( + deployment_group, + %{ + conditions: %{"tags" => ["beta", "rpi"], "version" => ""} + }, + user + ) assert ManagedDeployments.matched_devices_count(deployment_group, in_deployment: false) == 1 end test "devices outside deployment group account for platform and architecture", %{ + user: user, deployment_group: deployment_group, org: org, product: product, @@ -757,9 +923,13 @@ defmodule NervesHub.ManagedDeploymentsTest do refute device.deployment_id {:ok, deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{ - conditions: %{"tags" => ["beta", "rpi"], "version" => ""} - }) + ManagedDeployments.update_deployment_group( + deployment_group, + %{ + conditions: %{"tags" => ["beta", "rpi"], "version" => ""} + }, + user + ) assert ManagedDeployments.matched_devices_count(deployment_group, in_deployment: false) == 1 end @@ -769,7 +939,8 @@ defmodule NervesHub.ManagedDeploymentsTest do test "takes platform and architecture into account", %{ org: org, product: product, - firmware: firmware + firmware: firmware, + user: user } do {:ok, deployment_group} = ManagedDeployments.create_deployment_group( @@ -781,7 +952,8 @@ defmodule NervesHub.ManagedDeploymentsTest do }, firmware_id: firmware.id }, - product + product, + user ) _device1 = @@ -807,7 +979,8 @@ defmodule NervesHub.ManagedDeploymentsTest do test "matches against tags and version", %{ org: org, product: product, - firmware: firmware + firmware: firmware, + user: user } do {:ok, deployment_group} = ManagedDeployments.create_deployment_group( @@ -819,7 +992,8 @@ defmodule NervesHub.ManagedDeploymentsTest do }, firmware_id: firmware.id }, - product + product, + user ) _device1 = @@ -850,7 +1024,8 @@ defmodule NervesHub.ManagedDeploymentsTest do test "matches against only tags if deployment group has no version", %{ org: org, product: product, - firmware: firmware + firmware: firmware, + user: user } do {:ok, deployment_group} = ManagedDeployments.create_deployment_group( @@ -862,7 +1037,8 @@ defmodule NervesHub.ManagedDeploymentsTest do }, firmware_id: firmware.id }, - product + product, + user ) device1 = @@ -889,7 +1065,8 @@ defmodule NervesHub.ManagedDeploymentsTest do test "matches against only version if deployment group has no tags", %{ org: org, product: product, - firmware: firmware + firmware: firmware, + user: user } do {:ok, deployment_group} = ManagedDeployments.create_deployment_group( @@ -901,7 +1078,8 @@ defmodule NervesHub.ManagedDeploymentsTest do }, firmware_id: firmware.id }, - product + product, + user ) _device1 = @@ -928,7 +1106,8 @@ defmodule NervesHub.ManagedDeploymentsTest do %{ org: org, product: product, - firmware: firmware + firmware: firmware, + user: user } do {:ok, deployment_group} = ManagedDeployments.create_deployment_group( @@ -940,7 +1119,8 @@ defmodule NervesHub.ManagedDeploymentsTest do }, firmware_id: firmware.id }, - product + product, + user ) device1 = @@ -985,9 +1165,9 @@ defmodule NervesHub.ManagedDeploymentsTest do end end - test "should_run_orchestrator/0", %{deployment_group: deployment_group} do + test "should_run_orchestrator/0", %{user: user, deployment_group: deployment_group} do assert [] == ManagedDeployments.should_run_orchestrator() - {:ok, _} = ManagedDeployments.update_deployment_group(deployment_group, %{is_active: true}) + {:ok, _} = ManagedDeployments.update_deployment_group(deployment_group, %{is_active: true}, user) assert length(ManagedDeployments.should_run_orchestrator()) == 1 end diff --git a/test/nerves_hub_web/channels/device_channel_test.exs b/test/nerves_hub_web/channels/device_channel_test.exs index 2ca4b1036..d9e50f2a3 100644 --- a/test/nerves_hub_web/channels/device_channel_test.exs +++ b/test/nerves_hub_web/channels/device_channel_test.exs @@ -484,7 +484,7 @@ defmodule NervesHubWeb.DeviceChannelTest do refute device.deployment_id {:ok, deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{is_active: true}) + ManagedDeployments.update_deployment_group(deployment_group, %{is_active: true}, user) %{db_cert: certificate, cert: _cert} = Fixtures.device_certificate_fixture(device) @@ -505,9 +505,13 @@ defmodule NervesHubWeb.DeviceChannelTest do Devices.update_deployment_group(device, deployment_group) {:ok, _deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{ - conditions: %{"version" => "< 0.0.1"} - }) + ManagedDeployments.update_deployment_group( + deployment_group, + %{ + conditions: %{"version" => "< 0.0.1"} + }, + user + ) %{db_cert: certificate, cert: _cert} = Fixtures.device_certificate_fixture(device) @@ -614,7 +618,7 @@ defmodule NervesHubWeb.DeviceChannelTest do firmware = Fixtures.firmware_fixture(org_key, product, %{dir: System.tmp_dir()}) deployment_group = Fixtures.deployment_group_fixture(firmware) - ManagedDeployments.update_deployment_group(deployment_group, %{archive_id: archive.id}) + ManagedDeployments.update_deployment_group(deployment_group, %{archive_id: archive.id}, user) {device, _firmware, _deployment_group} = device_fixture(user, %{identifier: "123", deployment_id: deployment_group.id}) diff --git a/test/nerves_hub_web/channels/websocket_test.exs b/test/nerves_hub_web/channels/websocket_test.exs index e0fc00e4f..ada51a6da 100644 --- a/test/nerves_hub_web/channels/websocket_test.exs +++ b/test/nerves_hub_web/channels/websocket_test.exs @@ -673,7 +673,7 @@ defmodule NervesHubWeb.WebsocketTest do "tags" => ["beta"] } }) - |> ManagedDeployments.update_deployment_group(%{is_active: true}) + |> ManagedDeployments.update_deployment_group(%{is_active: true}, user) deployment_group = Repo.preload(deployment_group, :org) @@ -702,9 +702,13 @@ defmodule NervesHubWeb.WebsocketTest do Fixtures.firmware_fixture(org_key, firmware.product, %{version: "0.0.2", dir: tmp_dir}) {:ok, deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{ - firmware_id: new_firmware.id - }) + ManagedDeployments.update_deployment_group( + deployment_group, + %{ + firmware_id: new_firmware.id + }, + user + ) # This is what the orchestrator process will do Orchestrator.trigger_update(deployment_group) @@ -776,7 +780,7 @@ defmodule NervesHubWeb.WebsocketTest do "tags" => ["beta", "beta-edge"] } }) - |> ManagedDeployments.update_deployment_group(%{is_active: true}) + |> ManagedDeployments.update_deployment_group(%{is_active: true}, user) device = Fixtures.device_fixture( @@ -843,7 +847,7 @@ defmodule NervesHubWeb.WebsocketTest do "tags" => ["beta", "beta-edge"] } }) - |> ManagedDeployments.update_deployment_group(%{is_active: true}) + |> ManagedDeployments.update_deployment_group(%{is_active: true}, user) device = Fixtures.device_fixture( @@ -909,7 +913,7 @@ defmodule NervesHubWeb.WebsocketTest do "tags" => ["beta", "beta-edge"] } }) - |> ManagedDeployments.update_deployment_group(%{is_active: true}) + |> ManagedDeployments.update_deployment_group(%{is_active: true}, user) device = Fixtures.device_fixture( @@ -1141,7 +1145,7 @@ defmodule NervesHubWeb.WebsocketTest do "tags" => ["beta"] } }) - |> ManagedDeployments.update_deployment_group(%{is_active: true, archive_id: archive.id}) + |> ManagedDeployments.update_deployment_group(%{is_active: true, archive_id: archive.id}, user) device = Fixtures.device_fixture( @@ -1194,7 +1198,7 @@ defmodule NervesHubWeb.WebsocketTest do "tags" => ["beta"] } }) - |> ManagedDeployments.update_deployment_group(%{is_active: true, archive_id: archive.id}) + |> ManagedDeployments.update_deployment_group(%{is_active: true, archive_id: archive.id}, user) device = Fixtures.device_fixture( @@ -1251,7 +1255,7 @@ defmodule NervesHubWeb.WebsocketTest do "tags" => ["beta"] } }) - |> ManagedDeployments.update_deployment_group(%{is_active: true}) + |> ManagedDeployments.update_deployment_group(%{is_active: true}, user) device = Fixtures.device_fixture( @@ -1278,7 +1282,7 @@ defmodule NervesHubWeb.WebsocketTest do assert_online_and_available(device) {:ok, _deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{archive_id: archive.id}) + ManagedDeployments.update_deployment_group(deployment_group, %{archive_id: archive.id}, user) archive = SocketClient.wait_archive(socket) assert %{"url" => _, "version" => _} = archive diff --git a/test/nerves_hub_web/live/devices/show_test.exs b/test/nerves_hub_web/live/devices/show_test.exs index 7f45b6e0e..40a4c71d6 100644 --- a/test/nerves_hub_web/live/devices/show_test.exs +++ b/test/nerves_hub_web/live/devices/show_test.exs @@ -100,7 +100,7 @@ defmodule NervesHubWeb.Live.Devices.ShowTest do deployment_group: deployment_group } do {:ok, deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{is_active: true}) + ManagedDeployments.update_deployment_group(deployment_group, %{is_active: true}, fixture.user) # Set device status to :provisioned for deployment group eligibility %{status: :provisioned} = device = Devices.set_as_provisioned!(device) diff --git a/test/nerves_hub_web/live/new_ui/deployment_groups/show_test.exs b/test/nerves_hub_web/live/new_ui/deployment_groups/show_test.exs index c09890d40..0f1a733b7 100644 --- a/test/nerves_hub_web/live/new_ui/deployment_groups/show_test.exs +++ b/test/nerves_hub_web/live/new_ui/deployment_groups/show_test.exs @@ -46,14 +46,14 @@ defmodule NervesHubWeb.Live.NewUI.DeploymentGroups.ShowTest do context.conn |> visit("/org/#{org.name}/#{product.name}/deployment_groups/#{deployment_group.name}") - [ + %{ conn: conn, device: device, deployment_group: deployment_group, source_firmware: source_firmware, target_firmware: target_firmware, source_firmware_metadata: source_firmware_metadata - ] + } end test "empty state and displaying update stats", %{ @@ -114,7 +114,8 @@ defmodule NervesHubWeb.Live.NewUI.DeploymentGroups.ShowTest do org_key: org_key, product: product, deployment_group: deployment_group, - tmp_dir: tmp_dir + tmp_dir: tmp_dir, + user: user } do :ok = UpdateStats.log_update(device, source_firmware_metadata) @@ -124,9 +125,13 @@ defmodule NervesHubWeb.Live.NewUI.DeploymentGroups.ShowTest do {:ok, other_firmware_metadata} = Firmwares.metadata_from_firmware(other_firmware) {:ok, deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{ - firmware_id: other_firmware.id - }) + ManagedDeployments.update_deployment_group( + deployment_group, + %{ + firmware_id: other_firmware.id + }, + user + ) # deployment group needs to be explicitly passed in because association # is already preloaded from fixtures, causing the preload in log_update/2 diff --git a/test/support/fixtures.ex b/test/support/fixtures.ex index 986001eae..71ed6abd9 100644 --- a/test/support/fixtures.ex +++ b/test/support/fixtures.ex @@ -224,15 +224,20 @@ defmodule NervesHub.Fixtures do def deployment_group_fixture(%Firmwares.Firmware{} = firmware, params \\ %{}) do {is_active, params} = Map.pop(params, :is_active, false) + user = Map.get_lazy(params, :user, &user_fixture/0) {:ok, deployment_group} = params |> Map.put(:firmware_id, firmware.id) |> Enum.into(@deployment_group_params) - |> ManagedDeployments.create_deployment_group(%Product{id: firmware.product_id}) + |> ManagedDeployments.create_deployment_group(%Product{id: firmware.product_id}, user) {:ok, deployment_group} = - ManagedDeployments.update_deployment_group(deployment_group, %{is_active: is_active}) + ManagedDeployments.update_deployment_group( + deployment_group, + %{is_active: is_active}, + user + ) deployment_group end