From 37321588435d2cc8857705d5518018e798604785 Mon Sep 17 00:00:00 2001 From: Nelson Kopliku Date: Mon, 15 Apr 2024 16:41:34 +0200 Subject: [PATCH 1/4] Do not emit SoftwareUpdatesDiscoveryRequested when no fqdn is available --- lib/trento/hosts/host.ex | 6 ++++++ test/trento/hosts/host_test.exs | 27 +++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/lib/trento/hosts/host.ex b/lib/trento/hosts/host.ex index 62e0fdc788..7b33354565 100644 --- a/lib/trento/hosts/host.ex +++ b/lib/trento/hosts/host.ex @@ -548,6 +548,12 @@ defmodule Trento.Hosts.Host do # Software Updates Discovery + def execute( + %Host{fully_qualified_domain_name: nil}, + %DiscoverSoftwareUpdates{} + ), + do: [] + def execute( %Host{ host_id: host_id, diff --git a/test/trento/hosts/host_test.exs b/test/trento/hosts/host_test.exs index a34762d1dc..04def960d3 100644 --- a/test/trento/hosts/host_test.exs +++ b/test/trento/hosts/host_test.exs @@ -1607,6 +1607,33 @@ defmodule Trento.Hosts.HostTest do end end + test "should not trigger the software updates discovery process without a valid FQDN" do + host_id = Faker.UUID.v4() + + initial_events = [ + build(:host_registered_event, + host_id: host_id, + fully_qualified_domain_name: nil + ), + build(:heartbeat_succeded, host_id: host_id) + ] + + assert_events_and_state( + initial_events, + DiscoverSoftwareUpdates.new!(%{ + host_id: host_id + }), + [], + fn host -> + assert %Host{ + host_id: ^host_id, + fully_qualified_domain_name: nil, + heartbeat: Health.passing() + } = host + end + ) + end + test "should trigger the software updates discovery process" do host_id = Faker.UUID.v4() fully_qualified_domain_name = Faker.Internet.domain_name() From dd7e38acf1b3b9ff94a2a14128ce9069b9c5d5ff Mon Sep 17 00:00:00 2001 From: Nelson Kopliku Date: Mon, 15 Apr 2024 16:42:50 +0200 Subject: [PATCH 2/4] Make Discovery.discover_software_updates/0 issue DiscoverSoftwareUpdates commands instead of process completion --- lib/trento/software_updates/discovery.ex | 27 +-- .../software_updates/discovery_test.exs | 207 ++++-------------- 2 files changed, 56 insertions(+), 178 deletions(-) diff --git a/lib/trento/software_updates/discovery.ex b/lib/trento/software_updates/discovery.ex index 127c9fe39f..4aca3ae71c 100644 --- a/lib/trento/software_updates/discovery.ex +++ b/lib/trento/software_updates/discovery.ex @@ -7,7 +7,8 @@ defmodule Trento.SoftwareUpdates.Discovery do alias Trento.Hosts.Commands.{ ClearSoftwareUpdatesDiscovery, - CompleteSoftwareUpdatesDiscovery + CompleteSoftwareUpdatesDiscovery, + DiscoverSoftwareUpdates } alias Trento.Hosts.Projections.HostReadModel @@ -36,24 +37,14 @@ defmodule Trento.SoftwareUpdates.Discovery do def get_upgradable_packages(system_id), do: adapter().get_upgradable_packages(system_id) - @spec discover_software_updates :: {:ok, {list(), list()}} + @spec discover_software_updates :: :ok def discover_software_updates do - {:ok, - Hosts.get_all_hosts() - |> Enum.map(fn - %HostReadModel{id: host_id, fully_qualified_domain_name: fully_qualified_domain_name} -> - case discover_host_software_updates(host_id, fully_qualified_domain_name) do - {:error, error} -> - {:error, host_id, error} - - {:ok, _, _, _} = success -> - success - end - end) - |> Enum.split_with(fn - {:ok, _, _, _} -> true - _ -> false - end)} + Enum.each(Hosts.get_all_hosts(), fn + %HostReadModel{id: host_id} -> + %{host_id: host_id} + |> DiscoverSoftwareUpdates.new!() + |> commanded().dispatch() + end) end @spec clear_software_updates_discoveries :: :ok | {:error, any()} diff --git a/test/trento/software_updates/discovery_test.exs b/test/trento/software_updates/discovery_test.exs index 6b1f0ac49d..693465efae 100644 --- a/test/trento/software_updates/discovery_test.exs +++ b/test/trento/software_updates/discovery_test.exs @@ -8,10 +8,10 @@ defmodule Trento.SoftwareUpdates.DiscoveryTest do alias Trento.Hosts.Commands.{ ClearSoftwareUpdatesDiscovery, - CompleteSoftwareUpdatesDiscovery + CompleteSoftwareUpdatesDiscovery, + DiscoverSoftwareUpdates } - alias Trento.Hosts.ValueObjects.RelevantPatches alias Trento.SoftwareUpdates.Discovery alias Trento.SoftwareUpdates.Discovery.Mock, as: SoftwareUpdatesDiscoveryMock @@ -71,188 +71,75 @@ defmodule Trento.SoftwareUpdates.DiscoveryTest do describe "Discovering software updates for a collection of hosts" do test "should handle empty hosts list" do - assert {:ok, {[], []}} = Discovery.discover_software_updates() - end - - test "should handle hosts without fqdn" do - %{id: host_id1} = insert(:host, fully_qualified_domain_name: nil) - %{id: host_id2} = insert(:host, fully_qualified_domain_name: nil) - - {:ok, {[], errored_discoveries}} = Discovery.discover_software_updates() - - Enum.each([host_id1, host_id2], fn host_id -> - assert {:error, host_id, :host_without_fqdn} in errored_discoveries - end) - end - - test "should handle errors when getting a system id" do - %{id: host_id, fully_qualified_domain_name: fully_qualified_domain_name} = insert(:host) - - discovery_error = {:error, :some_error_while_getting_system_id} - - fail_on_getting_system_id(fully_qualified_domain_name, discovery_error) - - {:ok, {[], errored_discoveries}} = Discovery.discover_software_updates() - - assert {:error, host_id, discovery_error} in errored_discoveries - end - - test "should handle errors when getting relevant patches" do - %{id: host_id, fully_qualified_domain_name: fully_qualified_domain_name} = insert(:host) - - system_id = 100 - discovery_error = {:error, :some_error_while_getting_relevant_patches} - - fail_on_getting_relevant_patches(fully_qualified_domain_name, system_id, discovery_error) - - {:ok, {[], errored_discoveries}} = Discovery.discover_software_updates() - - assert {:error, host_id, discovery_error} in errored_discoveries - end - - test "should handle errors when dispatching discovery completion command" do - %{id: host_id, fully_qualified_domain_name: fully_qualified_domain_name} = insert(:host) - - system_id = 100 - - dispatching_error = {:error, :error_while_dispatching_completion_command} - - fail_on_dispatching_completion_command( - host_id, - fully_qualified_domain_name, - system_id, - dispatching_error + expect( + Trento.Commanded.Mock, + :dispatch, + 0, + fn _ -> :ok end ) - {:ok, {[], errored_discoveries}} = Discovery.discover_software_updates() - - assert {:error, host_id, dispatching_error} in errored_discoveries + assert :ok = Discovery.discover_software_updates() end - test "should complete discovery" do - %{id: host_id1, fully_qualified_domain_name: fully_qualified_domain_name1} = - insert(:host, hostname: "host1") - - %{id: host_id2, fully_qualified_domain_name: fully_qualified_domain_name2} = - insert(:host, hostname: "host2") - - %{id: host_id3, fully_qualified_domain_name: fully_qualified_domain_name3} = - insert(:host, hostname: "host3") - - %{id: host_id4} = insert(:host, fully_qualified_domain_name: nil) - - system_id1 = 100 - system_id2 = 101 - system_id3 = 102 - - system_ids = [ - system_id1, - system_id2, - system_id3 - ] - - fqdns = [ - fully_qualified_domain_name1, - fully_qualified_domain_name2, - fully_qualified_domain_name3 - ] - - {:ok, _} = Agent.start_link(fn -> 0 end, name: :get_system_id_iteration) + test "should issue software updates discovery in a best effort fashion" do + %{id: host_id1} = insert(:host, hostname: "host1") + %{id: host_id2} = insert(:host, hostname: "host2") + %{id: host_id3} = insert(:host, hostname: "host3") - expect( - SoftwareUpdatesDiscoveryMock, - :get_system_id, - 3, - fn fqdn -> - iteration = Agent.get(:get_system_id_iteration, & &1) - - assert fqdn == Enum.at(fqdns, iteration) - - Agent.update(:get_system_id_iteration, &(&1 + 1)) - - {:ok, Enum.at(system_ids, iteration)} - end + insert(:host, + hostname: "host4", + deregistered_at: DateTime.to_iso8601(Faker.DateTime.backward(2)) ) - discovered_relevant_patches = [ - %{advisory_type: AdvisoryType.security_advisory()}, - %{advisory_type: AdvisoryType.security_advisory()}, - %{advisory_type: AdvisoryType.bugfix()}, - %{advisory_type: AdvisoryType.enhancement()} - ] + %{id: host_id5} = insert(:host, hostname: "host5", fully_qualified_domain_name: nil) - {:ok, _} = Agent.start_link(fn -> 0 end, name: :get_relevant_patches_iteration) + {:ok, _} = Agent.start_link(fn -> 0 end, name: :command_dispatching_iteration) expect( - SoftwareUpdatesDiscoveryMock, - :get_relevant_patches, - 3, - fn system_id -> - iteration = Agent.get(:get_relevant_patches_iteration, & &1) + Trento.Commanded.Mock, + :dispatch, + 4, + fn command -> + iteration = Agent.get(:command_dispatching_iteration, & &1) - assert system_id == Enum.at(system_ids, iteration) + dispatching_result = + case iteration do + 0 -> + assert %DiscoverSoftwareUpdates{ + host_id: ^host_id1 + } = command - get_relevant_patches_result = - case system_id do - ^system_id2 -> {:error, :some_error} - _ -> {:ok, discovered_relevant_patches} - end + :ok - Agent.update(:get_relevant_patches_iteration, &(&1 + 1)) + 1 -> + assert %DiscoverSoftwareUpdates{ + host_id: ^host_id2 + } = command - get_relevant_patches_result - end - ) + :ok - expected_relevant_patches = %RelevantPatches{ - security_advisories: 2, - bug_fixes: 1, - software_enhancements: 1 - } + 2 -> + assert %DiscoverSoftwareUpdates{ + host_id: ^host_id3 + } = command - {:ok, _} = Agent.start_link(fn -> 0 end, name: :command_dispatching_iteration) + {:error, :some_error} - expect( - Trento.Commanded.Mock, - :dispatch, - 2, - fn command -> - iteration = Agent.get(:command_dispatching_iteration, & &1) + 3 -> + assert %DiscoverSoftwareUpdates{ + host_id: ^host_id5 + } = command - case iteration do - 0 -> - assert %CompleteSoftwareUpdatesDiscovery{ - host_id: ^host_id1, - relevant_patches: ^expected_relevant_patches - } = command - - 1 -> - assert %CompleteSoftwareUpdatesDiscovery{ - host_id: ^host_id3, - relevant_patches: ^expected_relevant_patches - } = command - end + :ok + end Agent.update(:command_dispatching_iteration, &(&1 + 1)) - :ok + dispatching_result end ) - assert {:ok, {successful_discoveries, errored_discoveries}} = - Discovery.discover_software_updates() - - assert length(successful_discoveries) == 2 - assert length(errored_discoveries) == 2 - - assert [ - {:ok, host_id1, system_id1, discovered_relevant_patches}, - {:ok, host_id3, system_id3, discovered_relevant_patches} - ] == - successful_discoveries - - assert {:error, host_id2, {:error, :some_error}} in errored_discoveries - assert {:error, host_id4, :host_without_fqdn} in errored_discoveries + assert :ok = Discovery.discover_software_updates() end end From 4aac0b7e28e996e7e310361200165550ea9ab4e8 Mon Sep 17 00:00:00 2001 From: Nelson Kopliku Date: Tue, 16 Apr 2024 14:10:23 +0200 Subject: [PATCH 3/4] Issue software updates discovery process for all the registered hosts when saving and updating settings --- lib/trento/software_updates.ex | 38 +++++++++++---------------- test/trento/software_updates_test.exs | 29 ++++++++++++++++++++ 2 files changed, 44 insertions(+), 23 deletions(-) diff --git a/lib/trento/software_updates.ex b/lib/trento/software_updates.ex index b382738316..b916595a96 100644 --- a/lib/trento/software_updates.ex +++ b/lib/trento/software_updates.ex @@ -44,7 +44,9 @@ defmodule Trento.SoftwareUpdates do | {:error, any()} def save_settings(settings_submission, date_service \\ DateService) do with {:ok, :settings_not_configured, settings} <- ensure_no_settings_configured() do - save_new_settings(settings, settings_submission, date_service) + settings + |> save_or_update_settings(settings_submission, date_service) + |> log_error("Error while saving software updates settings") end end @@ -54,7 +56,9 @@ defmodule Trento.SoftwareUpdates do | {:error, any()} def change_settings(settings_submission, date_service \\ DateService) do with {:ok, settings} <- get_settings() do - update_settings(settings, settings_submission, date_service) + settings + |> save_or_update_settings(settings_submission, date_service) + |> log_error("Error while updating software updates settings") end end @@ -97,7 +101,6 @@ defmodule Trento.SoftwareUpdates do case get_settings() do {:ok, _} -> Discovery.discover_software_updates() - :ok error -> Logger.error("Software updates settings not configured. Skipping discovery.") @@ -148,37 +151,26 @@ defmodule Trento.SoftwareUpdates do end end - defp save_new_settings(%Settings{} = settings, settings_submission, date_service) do - saving_result = + defp save_or_update_settings(%Settings{} = settings, settings_submission, date_service) do + result = settings |> Settings.changeset(settings_submission, date_service) |> Repo.update() - case saving_result do + case result do {:ok, _} = success -> + Discovery.discover_software_updates() success {:error, _} = error -> - Logger.error("Error while saving software updates settings: #{inspect(error)}") - error end end - defp update_settings(%Settings{} = settings, settings_submission, date_service) do - update_result = - settings - |> Settings.changeset(settings_submission, date_service) - |> Repo.update() - - case update_result do - {:ok, _} = success -> - success - - {:error, _} = error -> - Logger.error("Error while updating software updates settings: #{inspect(error)}") - - error - end + defp log_error({:error, _} = error, message) do + Logger.error("#{message}: #{inspect(error)}") + error end + + defp log_error(result, _), do: result end diff --git a/test/trento/software_updates_test.exs b/test/trento/software_updates_test.exs index 8970f491dc..3d06b74014 100644 --- a/test/trento/software_updates_test.exs +++ b/test/trento/software_updates_test.exs @@ -8,6 +8,7 @@ defmodule Trento.SoftwareUpdates.SettingsTest do import Trento.Factory + alias Trento.Hosts.Commands.DiscoverSoftwareUpdates alias Trento.SoftwareUpdates alias Trento.SoftwareUpdates.Settings @@ -195,6 +196,34 @@ defmodule Trento.SoftwareUpdates.SettingsTest do assert {:error, :settings_already_configured} = SoftwareUpdates.save_settings(settings) end + + test "should issue software updates discovery process when saving or updating settings" do + insert_list(5, :host) + insert(:host, deregistered_at: DateTime.to_iso8601(Faker.DateTime.backward(2))) + + operations = [ + &SoftwareUpdates.save_settings/1, + &SoftwareUpdates.change_settings/1 + ] + + for operation <- operations do + expect( + Trento.Commanded.Mock, + :dispatch, + 5, + fn %DiscoverSoftwareUpdates{} -> :ok end + ) + + settings = %{ + url: "https://valid.com", + username: Faker.Internet.user_name(), + password: Faker.Lorem.word(), + ca_cert: Faker.Lorem.sentence() + } + + assert {:ok, _} = operation.(settings) + end + end end describe "changing software updates settings" do From 153014a89c927f2288ddb94a62db0f359cc898b4 Mon Sep 17 00:00:00 2001 From: Nelson Kopliku Date: Tue, 16 Apr 2024 15:28:49 +0200 Subject: [PATCH 4/4] Revert changes on dispatching commands --- lib/trento/software_updates.ex | 1 + lib/trento/software_updates/discovery.ex | 27 ++- .../software_updates/discovery_test.exs | 207 ++++++++++++++---- test/trento/software_updates_test.exs | 4 +- 4 files changed, 181 insertions(+), 58 deletions(-) diff --git a/lib/trento/software_updates.ex b/lib/trento/software_updates.ex index b916595a96..a83ef12d70 100644 --- a/lib/trento/software_updates.ex +++ b/lib/trento/software_updates.ex @@ -101,6 +101,7 @@ defmodule Trento.SoftwareUpdates do case get_settings() do {:ok, _} -> Discovery.discover_software_updates() + :ok error -> Logger.error("Software updates settings not configured. Skipping discovery.") diff --git a/lib/trento/software_updates/discovery.ex b/lib/trento/software_updates/discovery.ex index 4aca3ae71c..127c9fe39f 100644 --- a/lib/trento/software_updates/discovery.ex +++ b/lib/trento/software_updates/discovery.ex @@ -7,8 +7,7 @@ defmodule Trento.SoftwareUpdates.Discovery do alias Trento.Hosts.Commands.{ ClearSoftwareUpdatesDiscovery, - CompleteSoftwareUpdatesDiscovery, - DiscoverSoftwareUpdates + CompleteSoftwareUpdatesDiscovery } alias Trento.Hosts.Projections.HostReadModel @@ -37,14 +36,24 @@ defmodule Trento.SoftwareUpdates.Discovery do def get_upgradable_packages(system_id), do: adapter().get_upgradable_packages(system_id) - @spec discover_software_updates :: :ok + @spec discover_software_updates :: {:ok, {list(), list()}} def discover_software_updates do - Enum.each(Hosts.get_all_hosts(), fn - %HostReadModel{id: host_id} -> - %{host_id: host_id} - |> DiscoverSoftwareUpdates.new!() - |> commanded().dispatch() - end) + {:ok, + Hosts.get_all_hosts() + |> Enum.map(fn + %HostReadModel{id: host_id, fully_qualified_domain_name: fully_qualified_domain_name} -> + case discover_host_software_updates(host_id, fully_qualified_domain_name) do + {:error, error} -> + {:error, host_id, error} + + {:ok, _, _, _} = success -> + success + end + end) + |> Enum.split_with(fn + {:ok, _, _, _} -> true + _ -> false + end)} end @spec clear_software_updates_discoveries :: :ok | {:error, any()} diff --git a/test/trento/software_updates/discovery_test.exs b/test/trento/software_updates/discovery_test.exs index 693465efae..6b1f0ac49d 100644 --- a/test/trento/software_updates/discovery_test.exs +++ b/test/trento/software_updates/discovery_test.exs @@ -8,10 +8,10 @@ defmodule Trento.SoftwareUpdates.DiscoveryTest do alias Trento.Hosts.Commands.{ ClearSoftwareUpdatesDiscovery, - CompleteSoftwareUpdatesDiscovery, - DiscoverSoftwareUpdates + CompleteSoftwareUpdatesDiscovery } + alias Trento.Hosts.ValueObjects.RelevantPatches alias Trento.SoftwareUpdates.Discovery alias Trento.SoftwareUpdates.Discovery.Mock, as: SoftwareUpdatesDiscoveryMock @@ -71,75 +71,188 @@ defmodule Trento.SoftwareUpdates.DiscoveryTest do describe "Discovering software updates for a collection of hosts" do test "should handle empty hosts list" do - expect( - Trento.Commanded.Mock, - :dispatch, - 0, - fn _ -> :ok end - ) + assert {:ok, {[], []}} = Discovery.discover_software_updates() + end + + test "should handle hosts without fqdn" do + %{id: host_id1} = insert(:host, fully_qualified_domain_name: nil) + %{id: host_id2} = insert(:host, fully_qualified_domain_name: nil) + + {:ok, {[], errored_discoveries}} = Discovery.discover_software_updates() + + Enum.each([host_id1, host_id2], fn host_id -> + assert {:error, host_id, :host_without_fqdn} in errored_discoveries + end) + end - assert :ok = Discovery.discover_software_updates() + test "should handle errors when getting a system id" do + %{id: host_id, fully_qualified_domain_name: fully_qualified_domain_name} = insert(:host) + + discovery_error = {:error, :some_error_while_getting_system_id} + + fail_on_getting_system_id(fully_qualified_domain_name, discovery_error) + + {:ok, {[], errored_discoveries}} = Discovery.discover_software_updates() + + assert {:error, host_id, discovery_error} in errored_discoveries end - test "should issue software updates discovery in a best effort fashion" do - %{id: host_id1} = insert(:host, hostname: "host1") - %{id: host_id2} = insert(:host, hostname: "host2") - %{id: host_id3} = insert(:host, hostname: "host3") + test "should handle errors when getting relevant patches" do + %{id: host_id, fully_qualified_domain_name: fully_qualified_domain_name} = insert(:host) + + system_id = 100 + discovery_error = {:error, :some_error_while_getting_relevant_patches} - insert(:host, - hostname: "host4", - deregistered_at: DateTime.to_iso8601(Faker.DateTime.backward(2)) + fail_on_getting_relevant_patches(fully_qualified_domain_name, system_id, discovery_error) + + {:ok, {[], errored_discoveries}} = Discovery.discover_software_updates() + + assert {:error, host_id, discovery_error} in errored_discoveries + end + + test "should handle errors when dispatching discovery completion command" do + %{id: host_id, fully_qualified_domain_name: fully_qualified_domain_name} = insert(:host) + + system_id = 100 + + dispatching_error = {:error, :error_while_dispatching_completion_command} + + fail_on_dispatching_completion_command( + host_id, + fully_qualified_domain_name, + system_id, + dispatching_error ) - %{id: host_id5} = insert(:host, hostname: "host5", fully_qualified_domain_name: nil) + {:ok, {[], errored_discoveries}} = Discovery.discover_software_updates() - {:ok, _} = Agent.start_link(fn -> 0 end, name: :command_dispatching_iteration) + assert {:error, host_id, dispatching_error} in errored_discoveries + end + + test "should complete discovery" do + %{id: host_id1, fully_qualified_domain_name: fully_qualified_domain_name1} = + insert(:host, hostname: "host1") + + %{id: host_id2, fully_qualified_domain_name: fully_qualified_domain_name2} = + insert(:host, hostname: "host2") + + %{id: host_id3, fully_qualified_domain_name: fully_qualified_domain_name3} = + insert(:host, hostname: "host3") + + %{id: host_id4} = insert(:host, fully_qualified_domain_name: nil) + + system_id1 = 100 + system_id2 = 101 + system_id3 = 102 + + system_ids = [ + system_id1, + system_id2, + system_id3 + ] + + fqdns = [ + fully_qualified_domain_name1, + fully_qualified_domain_name2, + fully_qualified_domain_name3 + ] + + {:ok, _} = Agent.start_link(fn -> 0 end, name: :get_system_id_iteration) expect( - Trento.Commanded.Mock, - :dispatch, - 4, - fn command -> - iteration = Agent.get(:command_dispatching_iteration, & &1) + SoftwareUpdatesDiscoveryMock, + :get_system_id, + 3, + fn fqdn -> + iteration = Agent.get(:get_system_id_iteration, & &1) - dispatching_result = - case iteration do - 0 -> - assert %DiscoverSoftwareUpdates{ - host_id: ^host_id1 - } = command + assert fqdn == Enum.at(fqdns, iteration) - :ok + Agent.update(:get_system_id_iteration, &(&1 + 1)) - 1 -> - assert %DiscoverSoftwareUpdates{ - host_id: ^host_id2 - } = command + {:ok, Enum.at(system_ids, iteration)} + end + ) - :ok + discovered_relevant_patches = [ + %{advisory_type: AdvisoryType.security_advisory()}, + %{advisory_type: AdvisoryType.security_advisory()}, + %{advisory_type: AdvisoryType.bugfix()}, + %{advisory_type: AdvisoryType.enhancement()} + ] - 2 -> - assert %DiscoverSoftwareUpdates{ - host_id: ^host_id3 - } = command + {:ok, _} = Agent.start_link(fn -> 0 end, name: :get_relevant_patches_iteration) - {:error, :some_error} + expect( + SoftwareUpdatesDiscoveryMock, + :get_relevant_patches, + 3, + fn system_id -> + iteration = Agent.get(:get_relevant_patches_iteration, & &1) - 3 -> - assert %DiscoverSoftwareUpdates{ - host_id: ^host_id5 - } = command + assert system_id == Enum.at(system_ids, iteration) - :ok + get_relevant_patches_result = + case system_id do + ^system_id2 -> {:error, :some_error} + _ -> {:ok, discovered_relevant_patches} end + Agent.update(:get_relevant_patches_iteration, &(&1 + 1)) + + get_relevant_patches_result + end + ) + + expected_relevant_patches = %RelevantPatches{ + security_advisories: 2, + bug_fixes: 1, + software_enhancements: 1 + } + + {:ok, _} = Agent.start_link(fn -> 0 end, name: :command_dispatching_iteration) + + expect( + Trento.Commanded.Mock, + :dispatch, + 2, + fn command -> + iteration = Agent.get(:command_dispatching_iteration, & &1) + + case iteration do + 0 -> + assert %CompleteSoftwareUpdatesDiscovery{ + host_id: ^host_id1, + relevant_patches: ^expected_relevant_patches + } = command + + 1 -> + assert %CompleteSoftwareUpdatesDiscovery{ + host_id: ^host_id3, + relevant_patches: ^expected_relevant_patches + } = command + end + Agent.update(:command_dispatching_iteration, &(&1 + 1)) - dispatching_result + :ok end ) - assert :ok = Discovery.discover_software_updates() + assert {:ok, {successful_discoveries, errored_discoveries}} = + Discovery.discover_software_updates() + + assert length(successful_discoveries) == 2 + assert length(errored_discoveries) == 2 + + assert [ + {:ok, host_id1, system_id1, discovered_relevant_patches}, + {:ok, host_id3, system_id3, discovered_relevant_patches} + ] == + successful_discoveries + + assert {:error, host_id2, {:error, :some_error}} in errored_discoveries + assert {:error, host_id4, :host_without_fqdn} in errored_discoveries end end diff --git a/test/trento/software_updates_test.exs b/test/trento/software_updates_test.exs index 3d06b74014..31d77bb1de 100644 --- a/test/trento/software_updates_test.exs +++ b/test/trento/software_updates_test.exs @@ -8,7 +8,7 @@ defmodule Trento.SoftwareUpdates.SettingsTest do import Trento.Factory - alias Trento.Hosts.Commands.DiscoverSoftwareUpdates + alias Trento.Hosts.Commands.CompleteSoftwareUpdatesDiscovery alias Trento.SoftwareUpdates alias Trento.SoftwareUpdates.Settings @@ -211,7 +211,7 @@ defmodule Trento.SoftwareUpdates.SettingsTest do Trento.Commanded.Mock, :dispatch, 5, - fn %DiscoverSoftwareUpdates{} -> :ok end + fn %CompleteSoftwareUpdatesDiscovery{} -> :ok end ) settings = %{