Skip to content

Commit

Permalink
chore(update_channel): better errors
Browse files Browse the repository at this point in the history
When creating and updating an update channel, target group ids are
validated to be available, meaning:
- they are present in the DB
- they are not related to any other update channel

closes edgehog-device-manager#529

Signed-off-by: Luca Zaninotto <[email protected]>
  • Loading branch information
lusergit committed Dec 12, 2024
1 parent ad4cb42 commit 332fea1
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 42 deletions.
8 changes: 8 additions & 0 deletions backend/lib/edgehog/groups/device_group/device_group.ex
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@ defmodule Edgehog.Groups.DeviceGroup do
accept [:update_channel_id]
end

update :assign_update_channel do
accept [:update_channel_id]

require_atomic? false

validate Validations.UpdateChannelAbsent
end

destroy :destroy do
description "Deletes a device group."
primary? true
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#
# This file is part of Edgehog.
#
# Copyright 2024 SECO Mind Srl
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#

defmodule Edgehog.Groups.DeviceGroup.Validations.UpdateChannelAbsent do
@moduledoc false
use Ash.Resource.Validation

@impl Ash.Resource.Validation
def validate(changeset, _opts, _context) do
device_group = changeset.data

if device_group.update_channel_id do
{:error,
field: :update_channel_id,
message: "The update channel is already set for the device group \"#{device_group.name}\"",
short_message: "Update channel already set"}
else
:ok
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -22,36 +22,13 @@ defmodule Edgehog.UpdateCampaigns.UpdateChannel.Changes.RelateTargetGroups do
@moduledoc false
use Ash.Resource.Change

alias Ash.Error.Changes.InvalidArgument
alias Edgehog.Groups.DeviceGroup

@impl Ash.Resource.Change
def change(changeset, _opts, context) do
%{tenant: tenant} = context

def change(changeset, _opts, _context) do
{:ok, target_group_ids} = Ash.Changeset.fetch_argument(changeset, :target_group_ids)

Ash.Changeset.after_action(changeset, fn _changeset, update_channel ->
relate_target_groups(tenant, update_channel, target_group_ids)
end)
end

defp relate_target_groups(tenant, update_channel, target_group_ids) do
%Ash.BulkResult{status: status, records: records} =
DeviceGroup
|> Ash.Query.filter(id in ^target_group_ids)
|> Ash.Query.filter(is_nil(update_channel_id))
|> Ash.Query.set_tenant(tenant)
|> Ash.bulk_update(:update_update_channel, %{update_channel_id: update_channel.id}, return_records?: true)

if status == :success and length(records) == length(target_group_ids) do
{:ok, update_channel}
else
{:error,
InvalidArgument.exception(
field: :target_group_ids,
message: "some target groups were not found or are already associated with an update channel"
)}
end
Ash.Changeset.manage_relationship(changeset, :target_groups, target_group_ids,
on_lookup: {:relate, :assign_update_channel},
on_no_match: :error
)
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ defmodule EdgehogWeb.Schema.Mutation.CreateUpdateChannelTest do
describe "createUpdateChannel mutation" do
test "creates update_channel with valid data", %{tenant: tenant} do
target_group = device_group_fixture(tenant: tenant)
assert target_group.update_channel_id == nil

target_group_id = AshGraphql.Resource.encode_relay_id(target_group)

Expand Down Expand Up @@ -176,15 +177,20 @@ defmodule EdgehogWeb.Schema.Mutation.CreateUpdateChannelTest do

assert %{
path: ["createUpdateChannel"],
fields: [:target_group_ids],
message: "some target groups were not found or are already associated with an update channel",
code: "invalid_argument"
fields: [:id],
message: "could not be found",
code: "not_found"
} = error
end

test "fails when trying to use already assigned target groups", %{tenant: tenant} do
target_group = device_group_fixture(tenant: tenant)
_ = update_channel_fixture(tenant: tenant, target_group_ids: [target_group.id])

_ =
update_channel_fixture(
tenant: tenant,
target_group_ids: [target_group.id]
)

target_group_id = AshGraphql.Resource.encode_relay_id(target_group)

Expand All @@ -195,10 +201,12 @@ defmodule EdgehogWeb.Schema.Mutation.CreateUpdateChannelTest do

assert %{
path: ["createUpdateChannel"],
fields: [:target_group_ids],
message: "some target groups were not found or are already associated with an update channel",
code: "invalid_argument"
fields: [:update_channel_id],
message: "The update channel is already set for the device group " <> name,
code: "invalid_attribute"
} = error

assert name == "\"#{target_group.name}\""
end
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,15 +154,17 @@ defmodule EdgehogWeb.Schema.Mutation.UpdateUpdateChannelTest do

assert %{
path: ["updateUpdateChannel"],
fields: [:target_group_ids],
code: "invalid_argument",
message: "some target groups were not found or are already associated with an update channel"
fields: [:id],
code: "not_found",
message: "could not be found"
} = error
end

test "fails when trying to use already assigned target groups", %{tenant: tenant, id: id} do
target_group = device_group_fixture(tenant: tenant)
_ = update_channel_fixture(tenant: tenant, target_group_ids: [target_group.id])

_ =
update_channel_fixture(tenant: tenant, target_group_ids: [target_group.id])

target_group_id = AshGraphql.Resource.encode_relay_id(target_group)

Expand All @@ -173,10 +175,12 @@ defmodule EdgehogWeb.Schema.Mutation.UpdateUpdateChannelTest do

assert %{
path: ["updateUpdateChannel"],
fields: [:target_group_ids],
code: "invalid_argument",
message: "some target groups were not found or are already associated with an update channel"
fields: [:update_channel_id],
code: "invalid_attribute",
message: "The update channel is already set for the device group " <> name
} = error

assert name == "\"#{target_group.name}\""
end
end

Expand Down

0 comments on commit 332fea1

Please sign in to comment.