diff --git a/lib/trento/sap_systems/commands/deregister_database_instance.ex b/lib/trento/databases/commands/deregister_database_instance.ex similarity index 74% rename from lib/trento/sap_systems/commands/deregister_database_instance.ex rename to lib/trento/databases/commands/deregister_database_instance.ex index f97ceb7ccf..939ac07efb 100644 --- a/lib/trento/sap_systems/commands/deregister_database_instance.ex +++ b/lib/trento/databases/commands/deregister_database_instance.ex @@ -1,4 +1,4 @@ -defmodule Trento.SapSystems.Commands.DeregisterDatabaseInstance do +defmodule Trento.Databases.Commands.DeregisterDatabaseInstance do @moduledoc """ Deregister (decommission) a database instance from the monitoring system. """ @@ -10,7 +10,7 @@ defmodule Trento.SapSystems.Commands.DeregisterDatabaseInstance do defcommand do field :instance_number, :string field :host_id, Ecto.UUID - field :sap_system_id, Ecto.UUID + field :database_id, Ecto.UUID field :deregistered_at, :utc_datetime_usec end end diff --git a/lib/trento/sap_systems/commands/mark_database_instance_absent.ex b/lib/trento/databases/commands/mark_database_instance_absent.ex similarity index 70% rename from lib/trento/sap_systems/commands/mark_database_instance_absent.ex rename to lib/trento/databases/commands/mark_database_instance_absent.ex index 261eef70bf..4b6e367491 100644 --- a/lib/trento/sap_systems/commands/mark_database_instance_absent.ex +++ b/lib/trento/databases/commands/mark_database_instance_absent.ex @@ -1,4 +1,4 @@ -defmodule Trento.SapSystems.Commands.MarkDatabaseInstanceAbsent do +defmodule Trento.Databases.Commands.MarkDatabaseInstanceAbsent do @moduledoc """ Mark a database instance as absent """ @@ -9,7 +9,7 @@ defmodule Trento.SapSystems.Commands.MarkDatabaseInstanceAbsent do defcommand do field :instance_number, :string field :host_id, Ecto.UUID - field :sap_system_id, Ecto.UUID + field :database_id, Ecto.UUID field :absent_at, :utc_datetime_usec end end diff --git a/lib/trento/sap_systems/commands/register_database_instance.ex b/lib/trento/databases/commands/register_database_instance.ex similarity index 86% rename from lib/trento/sap_systems/commands/register_database_instance.ex rename to lib/trento/databases/commands/register_database_instance.ex index 7b19cd96ad..3aa1a984ed 100644 --- a/lib/trento/sap_systems/commands/register_database_instance.ex +++ b/lib/trento/databases/commands/register_database_instance.ex @@ -1,10 +1,10 @@ -defmodule Trento.SapSystems.Commands.RegisterDatabaseInstance do +defmodule Trento.Databases.Commands.RegisterDatabaseInstance do @moduledoc """ Register a database instance to the monitoring system. """ @required_fields [ - :sap_system_id, + :database_id, :sid, :tenant, :host_id, @@ -20,7 +20,7 @@ defmodule Trento.SapSystems.Commands.RegisterDatabaseInstance do require Trento.Enums.Health, as: Health defcommand do - field :sap_system_id, Ecto.UUID + field :database_id, Ecto.UUID field :sid, :string field :tenant, :string field :host_id, Ecto.UUID diff --git a/lib/trento/databases/database.ex b/lib/trento/databases/database.ex new file mode 100644 index 0000000000..30eee673d1 --- /dev/null +++ b/lib/trento/databases/database.ex @@ -0,0 +1,627 @@ +defmodule Trento.Databases.Database do + @moduledoc """ + The database aggregate manages all the domain logic related to + deployed HANA database. + + In order to have a fully registered database one of the next two conditions must exist: + - A HANA instance without system replication is discovered + - A HANA instance running as primary system replication instance is discovered + + Once any of these conditions are met the Database is registered and all the events related + to it are available now. + """ + + require Trento.Enums.Health, as: Health + + alias Commanded.Aggregate.Multi + + alias Trento.Databases.Database + + alias Trento.SapSystems.Instance + + alias Trento.Databases.Commands.{ + DeregisterDatabaseInstance, + MarkDatabaseInstanceAbsent, + RegisterDatabaseInstance + } + + alias Trento.SapSystems.Events.{ + DatabaseDeregistered, + DatabaseHealthChanged, + DatabaseInstanceDeregistered, + DatabaseInstanceHealthChanged, + DatabaseInstanceMarkedAbsent, + DatabaseInstanceMarkedPresent, + DatabaseInstanceRegistered, + DatabaseInstanceSystemReplicationChanged, + DatabaseRegistered, + DatabaseRestored + } + + alias Trento.Services.HealthService + + @required_fields [] + + use Trento.Support.Type + + deftype do + field :database_id, Ecto.UUID + field :sid, :string, default: nil + field :health, Ecto.Enum, values: Health.values() + field :deregistered_at, :utc_datetime_usec, default: nil + + embeds_many :instances, Instance + end + + def execute( + %Database{database_id: nil}, + %RegisterDatabaseInstance{ + system_replication: "Secondary" + } + ), + do: {:error, :database_not_registered} + + # First time that a Database instance is registered, the Database starts its registration process. + # Database instances are accepted when the system replication is disabled or when enabled, only if the database + # has a primary role + def execute( + %Database{database_id: nil}, + %RegisterDatabaseInstance{ + database_id: database_id, + sid: sid, + tenant: tenant, + host_id: host_id, + instance_number: instance_number, + instance_hostname: instance_hostname, + features: features, + http_port: http_port, + https_port: https_port, + start_priority: start_priority, + system_replication: system_replication, + system_replication_status: system_replication_status, + health: health + } + ) do + [ + %DatabaseRegistered{ + sap_system_id: database_id, + sid: sid, + health: health + }, + %DatabaseInstanceRegistered{ + sap_system_id: database_id, + sid: sid, + tenant: tenant, + instance_number: instance_number, + instance_hostname: instance_hostname, + features: features, + http_port: http_port, + https_port: https_port, + start_priority: start_priority, + host_id: host_id, + system_replication: system_replication, + system_replication_status: system_replication_status, + health: health + } + ] + end + + # Database restore + def execute( + %Database{deregistered_at: deregistered_at}, + %RegisterDatabaseInstance{ + system_replication: "Secondary" + } + ) + when not is_nil(deregistered_at), + do: {:error, :database_not_registered} + + # When a deregistered database is present, we add the new database instance + # and restore the database, the conditions are the same as registration + def execute( + %Database{deregistered_at: deregistered_at}, + %RegisterDatabaseInstance{ + database_id: database_id, + sid: sid, + tenant: tenant, + host_id: host_id, + instance_number: instance_number, + instance_hostname: instance_hostname, + features: features, + http_port: http_port, + https_port: https_port, + start_priority: start_priority, + system_replication: system_replication, + system_replication_status: system_replication_status, + health: health + } + ) + when not is_nil(deregistered_at) do + [ + %DatabaseInstanceRegistered{ + sap_system_id: database_id, + sid: sid, + tenant: tenant, + instance_number: instance_number, + instance_hostname: instance_hostname, + features: features, + http_port: http_port, + https_port: https_port, + start_priority: start_priority, + host_id: host_id, + system_replication: system_replication, + system_replication_status: system_replication_status, + health: health + }, + %DatabaseRestored{ + sap_system_id: database_id, + health: health + } + ] + end + + # When a RegisterDatabaseInstance command is received by an existing database aggregate, + # the database aggregate registers the Database instance if it is not already registered + # and updates the health when needed. + def execute( + %Database{instances: instances} = database, + %RegisterDatabaseInstance{host_id: host_id, instance_number: instance_number} = command + ) do + instance = get_instance(instances, host_id, instance_number) + + database + |> Multi.new() + |> Multi.execute(fn _ -> + maybe_emit_database_instance_system_replication_changed_event(instance, command) + end) + |> Multi.execute(fn _ -> + maybe_emit_database_instance_health_changed_event(instance, command) + end) + |> Multi.execute(fn _ -> + maybe_emit_database_instance_registered_event(instance, command) + end) + |> Multi.execute(fn _ -> + maybe_emit_database_instance_marked_present_event(instance, command) + end) + |> Multi.execute(&maybe_emit_database_health_changed_event/1) + end + + def execute( + %Database{database_id: nil}, + _ + ) do + {:error, :database_not_registered} + end + + def execute( + %Database{database_id: database_id, instances: instances}, + %MarkDatabaseInstanceAbsent{ + instance_number: instance_number, + host_id: host_id, + absent_at: absent_at + } + ) do + case get_instance(instances, host_id, instance_number) do + %Instance{absent_at: nil} -> + %DatabaseInstanceMarkedAbsent{ + instance_number: instance_number, + host_id: host_id, + sap_system_id: database_id, + absent_at: absent_at + } + + _ -> + nil + end + end + + # Deregister a database instance and emit a DatabaseInstanceDeregistered + # also potentially emit DatabaseDeregistered events + def execute( + %Database{database_id: database_id} = database, + %DeregisterDatabaseInstance{ + database_id: database_id, + deregistered_at: deregistered_at + } = instance + ) do + database + |> Multi.new() + |> Multi.execute(fn _ -> + maybe_emit_database_instance_deregistered_event(database, instance) + end) + |> Multi.execute(fn database -> + maybe_emit_database_deregistered_event(database, deregistered_at) + end) + end + + def execute( + %Database{deregistered_at: deregistered_at}, + _ + ) + when not is_nil(deregistered_at) do + {:error, :database_not_registered} + end + + def apply( + %Database{database_id: nil}, + %DatabaseRegistered{ + sap_system_id: database_id, + sid: sid, + health: health + } + ) do + %Database{ + database_id: database_id, + sid: sid, + health: health + } + end + + def apply( + %Database{instances: instances} = database, + %DatabaseInstanceRegistered{ + sid: sid, + system_replication: system_replication, + system_replication_status: system_replication_status, + instance_number: instance_number, + features: features, + host_id: host_id, + health: health + } + ) do + instances = [ + %Instance{ + sid: sid, + system_replication: system_replication, + system_replication_status: system_replication_status, + instance_number: instance_number, + features: features, + host_id: host_id, + health: health, + absent_at: nil + } + | instances + ] + + %Database{database | instances: instances} + end + + def apply( + %Database{instances: instances} = database, + %DatabaseInstanceSystemReplicationChanged{ + host_id: host_id, + instance_number: instance_number, + system_replication: system_replication, + system_replication_status: system_replication_status + } + ) do + instances = + Enum.map( + instances, + fn + %Instance{host_id: ^host_id, instance_number: ^instance_number} = instance -> + %Instance{ + instance + | system_replication: system_replication, + system_replication_status: system_replication_status + } + + instance -> + instance + end + ) + + %Database{database | instances: instances} + end + + def apply( + %Database{instances: instances} = database, + %DatabaseInstanceHealthChanged{ + host_id: host_id, + instance_number: instance_number, + health: health + } + ) do + instances = + Enum.map( + instances, + fn + %Instance{host_id: ^host_id, instance_number: ^instance_number} = instance -> + %Instance{instance | health: health} + + instance -> + instance + end + ) + + %Database{database | instances: instances} + end + + def apply(%Database{} = database, %DatabaseHealthChanged{ + health: health + }) do + %Database{database | health: health} + end + + def apply( + %Database{instances: instances} = database, + %DatabaseInstanceMarkedPresent{ + instance_number: instance_number, + host_id: host_id + } + ) do + instances = update_instance(instances, instance_number, host_id, %{absent_at: nil}) + + %Database{database | instances: instances} + end + + def apply( + %Database{instances: instances} = database, + %DatabaseInstanceMarkedAbsent{ + instance_number: instance_number, + host_id: host_id, + absent_at: absent_at + } + ) do + instances = update_instance(instances, instance_number, host_id, %{absent_at: absent_at}) + + %Database{database | instances: instances} + end + + def apply( + %Database{instances: instances} = database, + %DatabaseInstanceDeregistered{ + instance_number: instance_number, + host_id: host_id + } + ) do + instances = + Enum.reject(instances, fn + %Instance{instance_number: ^instance_number, host_id: ^host_id} -> + true + + _ -> + false + end) + + %Database{database | instances: instances} + end + + def apply( + %Database{} = database, + %DatabaseDeregistered{deregistered_at: deregistered_at} + ) do + %Database{database | deregistered_at: deregistered_at} + end + + def apply( + %Database{} = database, + %DatabaseRestored{ + health: health + } + ) do + %Database{ + database + | health: health, + deregistered_at: nil + } + end + + defp maybe_emit_database_instance_registered_event( + nil, + %RegisterDatabaseInstance{ + database_id: database_id, + sid: sid, + tenant: tenant, + instance_number: instance_number, + instance_hostname: instance_hostname, + features: features, + http_port: http_port, + https_port: https_port, + start_priority: start_priority, + host_id: host_id, + system_replication: system_replication, + system_replication_status: system_replication_status, + health: health + } + ) do + %DatabaseInstanceRegistered{ + sap_system_id: database_id, + sid: sid, + tenant: tenant, + instance_number: instance_number, + instance_hostname: instance_hostname, + features: features, + http_port: http_port, + https_port: https_port, + start_priority: start_priority, + host_id: host_id, + system_replication: system_replication, + system_replication_status: system_replication_status, + health: health + } + end + + defp maybe_emit_database_instance_registered_event(_, _), do: nil + + defp maybe_emit_database_instance_marked_present_event( + %Instance{absent_at: nil}, + %RegisterDatabaseInstance{} + ), + do: nil + + defp maybe_emit_database_instance_marked_present_event( + %Instance{ + instance_number: instance_number, + host_id: host_id + }, + %RegisterDatabaseInstance{database_id: database_id} + ) do + %DatabaseInstanceMarkedPresent{ + instance_number: instance_number, + host_id: host_id, + sap_system_id: database_id + } + end + + defp maybe_emit_database_instance_marked_present_event(_, _), do: nil + + defp maybe_emit_database_instance_system_replication_changed_event( + %Instance{ + system_replication: system_replication, + system_replication_status: system_replication_status + }, + %RegisterDatabaseInstance{ + database_id: database_id, + host_id: host_id, + instance_number: instance_number, + system_replication: new_system_replication, + system_replication_status: new_system_replication_status + } + ) + when system_replication != new_system_replication or + system_replication_status != new_system_replication_status do + %DatabaseInstanceSystemReplicationChanged{ + sap_system_id: database_id, + host_id: host_id, + instance_number: instance_number, + system_replication: new_system_replication, + system_replication_status: new_system_replication_status + } + end + + defp maybe_emit_database_instance_system_replication_changed_event(_, _), do: nil + + defp maybe_emit_database_instance_health_changed_event( + %Instance{ + health: health + }, + %RegisterDatabaseInstance{ + database_id: database_id, + host_id: host_id, + instance_number: instance_number, + health: new_health + } + ) + when health != new_health do + %DatabaseInstanceHealthChanged{ + sap_system_id: database_id, + host_id: host_id, + instance_number: instance_number, + health: new_health + } + end + + defp maybe_emit_database_instance_health_changed_event(_, _), do: nil + + # Returns a DatabaseHealthChanged event if the newly computed aggregated health of all the instances + # is different from the previous Database health. + defp maybe_emit_database_health_changed_event(%Database{ + database_id: database_id, + instances: instances, + health: health + }) do + new_health = + instances + |> Enum.map(& &1.health) + |> HealthService.compute_aggregated_health() + + if new_health != health do + %DatabaseHealthChanged{ + sap_system_id: database_id, + health: new_health + } + end + end + + defp maybe_emit_database_instance_deregistered_event( + %Database{instances: []}, + %DeregisterDatabaseInstance{} + ), + do: {:error, :database_instance_not_registered} + + defp maybe_emit_database_instance_deregistered_event( + %Database{instances: instances}, + %DeregisterDatabaseInstance{ + database_id: database_id, + host_id: host_id, + instance_number: instance_number, + deregistered_at: deregistered_at + } + ) do + case get_instance(instances, host_id, instance_number) do + nil -> + {:error, :database_instance_not_registered} + + _ -> + %DatabaseInstanceDeregistered{ + sap_system_id: database_id, + instance_number: instance_number, + host_id: host_id, + deregistered_at: deregistered_at + } + end + end + + defp maybe_emit_database_deregistered_event( + %Database{ + database_id: database_id, + deregistered_at: nil, + instances: [] + }, + deregistered_at + ) do + %DatabaseDeregistered{sap_system_id: database_id, deregistered_at: deregistered_at} + end + + defp maybe_emit_database_deregistered_event( + %Database{ + database_id: database_id, + instances: instances, + deregistered_at: nil + }, + deregistered_at + ) do + has_primary? = + Enum.any?(instances, fn %{system_replication: system_replication} -> + system_replication == "Primary" + end) + + has_secondary? = + Enum.any?(instances, fn %{system_replication: system_replication} -> + system_replication == "Secondary" + end) + + if has_secondary? and !has_primary? do + %DatabaseDeregistered{ + sap_system_id: database_id, + deregistered_at: deregistered_at + } + end + end + + defp maybe_emit_database_deregistered_event(_, _), do: nil + + defp get_instance(instances, host_id, instance_number) do + Enum.find(instances, fn + %Instance{host_id: ^host_id, instance_number: ^instance_number} -> + true + + _ -> + false + end) + end + + defp update_instance(instances, instance_number, host_id, fields) do + Enum.map( + instances, + fn + %Instance{instance_number: ^instance_number, host_id: ^host_id} = instance -> + Kernel.struct(instance, fields) + + instance -> + instance + end + ) + end +end diff --git a/lib/trento/databases/lifespan.ex b/lib/trento/databases/lifespan.ex new file mode 100644 index 0000000000..3e9dce263b --- /dev/null +++ b/lib/trento/databases/lifespan.ex @@ -0,0 +1,17 @@ +defmodule Trento.Databases.Lifespan do + @moduledoc """ + Database aggregate lifespan. + + It controls the lifespan of the aggregate GenServer representing a database. + """ + + @behaviour Commanded.Aggregates.AggregateLifespan + + alias Commanded.Aggregates.DefaultLifespan + + def after_event(event), do: DefaultLifespan.after_event(event) + + def after_command(command), do: DefaultLifespan.after_command(command) + + def after_error(error), do: DefaultLifespan.after_error(error) +end diff --git a/lib/trento/discovery/policies/sap_system_policy.ex b/lib/trento/discovery/policies/sap_system_policy.ex index bc64e94af9..5a9c4a3c62 100644 --- a/lib/trento/discovery/policies/sap_system_policy.ex +++ b/lib/trento/discovery/policies/sap_system_policy.ex @@ -5,15 +5,16 @@ defmodule Trento.Discovery.Policies.SapSystemPolicy do require Trento.SapSystems.Enums.EnsaVersion, as: EnsaVersion - alias Trento.SapSystems.Commands.{ - DeregisterApplicationInstance, - DeregisterDatabaseInstance, - MarkApplicationInstanceAbsent, + alias Trento.Databases.Commands.{ MarkDatabaseInstanceAbsent, - RegisterApplicationInstance, RegisterDatabaseInstance } + alias Trento.SapSystems.Commands.{ + MarkApplicationInstanceAbsent, + RegisterApplicationInstance + } + alias Trento.SapSystems.Projections.{ApplicationInstanceReadModel, DatabaseInstanceReadModel} alias Trento.Discovery.Payloads.SapSystemDiscoveryPayload @@ -39,9 +40,7 @@ defmodule Trento.Discovery.Policies.SapSystemPolicy do ) :: {:ok, [ - DeregisterApplicationInstance.t() - | DeregisterDatabaseInstance.t() - | RegisterApplicationInstance.t() + RegisterApplicationInstance.t() | RegisterDatabaseInstance.t() ]} | {:error, any} @@ -97,7 +96,7 @@ defmodule Trento.Discovery.Policies.SapSystemPolicy do Enum.flat_map(databases, fn %{:Database => tenant} -> Enum.map(instances, fn instance -> RegisterDatabaseInstance.new(%{ - sap_system_id: UUID.uuid5(@uuid_namespace, id), + database_id: UUID.uuid5(@uuid_namespace, id), sid: sid, tenant: tenant, host_id: host_id, @@ -171,7 +170,7 @@ defmodule Trento.Discovery.Policies.SapSystemPolicy do MarkDatabaseInstanceAbsent.new!(%{ host_id: instance.host_id, instance_number: instance.instance_number, - sap_system_id: instance.sap_system_id, + database_id: instance.sap_system_id, absent_at: DateTime.utc_now() }) end) diff --git a/lib/trento/infrastructure/commanded/middleware/enrich_register_application_instance.ex b/lib/trento/infrastructure/commanded/middleware/enrich_register_application_instance.ex index 68002ef59c..21e6b40d26 100644 --- a/lib/trento/infrastructure/commanded/middleware/enrich_register_application_instance.ex +++ b/lib/trento/infrastructure/commanded/middleware/enrich_register_application_instance.ex @@ -18,7 +18,8 @@ defimpl Trento.Infrastructure.Commanded.Middleware.Enrichable, case Repo.one(query) do %DatabaseInstanceReadModel{sap_system_id: sap_system_id} -> - {:ok, %RegisterApplicationInstance{command | sap_system_id: sap_system_id}} + {:ok, + %RegisterApplicationInstance{command | sap_system_id: UUID.uuid5(sap_system_id, tenant)}} nil -> {:error, :database_not_registered} diff --git a/lib/trento/infrastructure/commanded/process_managers/deregistration_process_manager.ex b/lib/trento/infrastructure/commanded/process_managers/deregistration_process_manager.ex index 3a4bf33b1a..174eeef772 100644 --- a/lib/trento/infrastructure/commanded/process_managers/deregistration_process_manager.ex +++ b/lib/trento/infrastructure/commanded/process_managers/deregistration_process_manager.ex @@ -60,10 +60,8 @@ defmodule Trento.Infrastructure.Commanded.ProcessManagers.DeregistrationProcessM alias Trento.Hosts.Commands.DeregisterHost - alias Trento.SapSystems.Commands.{ - DeregisterApplicationInstance, - DeregisterDatabaseInstance - } + alias Trento.Databases.Commands.DeregisterDatabaseInstance + alias Trento.SapSystems.Commands.DeregisterApplicationInstance alias Trento.Clusters.Commands.DeregisterClusterHost @@ -97,13 +95,12 @@ defmodule Trento.Infrastructure.Commanded.ProcessManagers.DeregistrationProcessM def interested?(%SapSystemRolledUp{ snapshot: %SapSystem{ - database: %SapSystems.Database{instances: db_instances}, - application: %SapSystems.Application{instances: app_instances} + instances: app_instances } }), do: {:start, - (db_instances ++ app_instances) + app_instances |> Enum.map(fn %SapSystems.Instance{host_id: host_id} -> host_id end) |> Enum.uniq()} @@ -148,7 +145,7 @@ defmodule Trento.Infrastructure.Commanded.ProcessManagers.DeregistrationProcessM instance_number: instance_number } -> %DeregisterDatabaseInstance{ - sap_system_id: sap_system_id, + database_id: sap_system_id, instance_number: instance_number, host_id: host_id, deregistered_at: requested_at @@ -230,27 +227,15 @@ defmodule Trento.Infrastructure.Commanded.ProcessManagers.DeregistrationProcessM def apply( %DeregistrationProcessManager{ - database_instances: database_instances, application_instances: application_instances } = state, %SapSystemRolledUp{ sap_system_id: snapshot_sap_system_id, snapshot: %SapSystem{ - database: %SapSystems.Database{instances: snapshot_database_instances}, - application: %SapSystems.Application{instances: snapshot_application_instances} + instances: snapshot_application_instances } } ) do - new_database_instances = - snapshot_database_instances - |> Enum.map(fn %SapSystems.Instance{ - instance_number: instance_number - } -> - %Instance{sap_system_id: snapshot_sap_system_id, instance_number: instance_number} - end) - |> Enum.concat(database_instances) - |> Enum.uniq() - new_application_instances = snapshot_application_instances |> Enum.map(fn %SapSystems.Instance{ @@ -263,8 +248,7 @@ defmodule Trento.Infrastructure.Commanded.ProcessManagers.DeregistrationProcessM %DeregistrationProcessManager{ state - | database_instances: new_database_instances, - application_instances: new_application_instances + | application_instances: new_application_instances } end diff --git a/lib/trento/router.ex b/lib/trento/router.ex index e600889fda..0a565d48f2 100644 --- a/lib/trento/router.ex +++ b/lib/trento/router.ex @@ -26,17 +26,21 @@ defmodule Trento.Router do UpdateSlesSubscriptions } + alias Trento.Databases.Commands.{ + DeregisterDatabaseInstance, + MarkDatabaseInstanceAbsent, + RegisterDatabaseInstance + } + alias Trento.SapSystems.Commands.{ DeregisterApplicationInstance, - DeregisterDatabaseInstance, MarkApplicationInstanceAbsent, - MarkDatabaseInstanceAbsent, RegisterApplicationInstance, - RegisterDatabaseInstance, RollUpSapSystem } alias Trento.Clusters + alias Trento.Databases alias Trento.Hosts alias Trento.SapSystems @@ -78,13 +82,20 @@ defmodule Trento.Router do dispatch [ DeregisterApplicationInstance, - DeregisterDatabaseInstance, MarkApplicationInstanceAbsent, - MarkDatabaseInstanceAbsent, RegisterApplicationInstance, - RegisterDatabaseInstance, RollUpSapSystem ], to: SapSystems.SapSystem, lifespan: SapSystems.Lifespan + + identify Databases.Database, by: :database_id + + dispatch [ + DeregisterDatabaseInstance, + MarkDatabaseInstanceAbsent, + RegisterDatabaseInstance + ], + to: Databases.Database, + lifespan: Databases.Lifespan end diff --git a/lib/trento/sap_systems.ex b/lib/trento/sap_systems.ex index 6173fc170b..c035a4d796 100644 --- a/lib/trento/sap_systems.ex +++ b/lib/trento/sap_systems.ex @@ -14,10 +14,9 @@ defmodule Trento.SapSystems do alias Trento.Support.DateService - alias Trento.SapSystems.Commands.{ - DeregisterApplicationInstance, - DeregisterDatabaseInstance - } + alias Trento.Databases.Commands.DeregisterDatabaseInstance + + alias Trento.SapSystems.Commands.DeregisterApplicationInstance alias Trento.Repo @@ -107,7 +106,7 @@ defmodule Trento.SapSystems do _ -> commanded().dispatch( DeregisterDatabaseInstance.new!(%{ - sap_system_id: sap_system_id, + database_id: sap_system_id, host_id: host_id, instance_number: instance_number, deregistered_at: date_service.utc_now() diff --git a/lib/trento/sap_systems/application.ex b/lib/trento/sap_systems/application.ex deleted file mode 100644 index 2071b6d9f7..0000000000 --- a/lib/trento/sap_systems/application.ex +++ /dev/null @@ -1,16 +0,0 @@ -defmodule Trento.SapSystems.Application do - @moduledoc """ - This module represents a SAP System application. - """ - - alias Trento.SapSystems.Instance - - @required_fields [] - - use Trento.Support.Type - - deftype do - field :sid, :string - embeds_many :instances, Instance - end -end diff --git a/lib/trento/sap_systems/database.ex b/lib/trento/sap_systems/database.ex deleted file mode 100644 index f21e00beec..0000000000 --- a/lib/trento/sap_systems/database.ex +++ /dev/null @@ -1,20 +0,0 @@ -defmodule Trento.SapSystems.Database do - @moduledoc """ - This module represents a SAP System database. - """ - - require Trento.Enums.Health, as: Health - - alias Trento.SapSystems.Instance - - @required_fields [] - - use Trento.Support.Type - - deftype do - field :sid, :string - embeds_many :instances, Instance - field :deregistered_at, :utc_datetime_usec - field :health, Ecto.Enum, values: Health.values() - end -end diff --git a/lib/trento/sap_systems/sap_system.ex b/lib/trento/sap_systems/sap_system.ex index 361c0d2713..c19f47f287 100644 --- a/lib/trento/sap_systems/sap_system.ex +++ b/lib/trento/sap_systems/sap_system.ex @@ -1,15 +1,12 @@ defmodule Trento.SapSystems.SapSystem do @moduledoc """ The SAP system aggregate manages all the domain logic related to - deployed SAP systems, which are composed by a database and application layers. - **The HANA database is the only supported database type.** + deployed SAP systems, which is composed by the application layer. - In order to have a fully registered SAP system, both the database and application - composing this system must be registered. + In order to have a fully registered SAP system, the database aggregate containing + this application tenant and application must be registered in the database aggregate. The minimum set of application features is ABAP and MESSAGESERVER. Otherwise, a complete SAP system cannot exist. - And each of the two layers might be composed by multiple instances altogether. - This means that a SAP system aggregate state can have multiple application/database instances. - + This means that a SAP system aggregate state can have multiple application instances. ## SAP instance @@ -17,31 +14,26 @@ defmodule Trento.SapSystems.SapSystem do particular host. So the instance runs entirely in one host, but on the other hand multiple different SAP instances might be running in the same host. - For example, a HANA database might be composed by two database instances - that are working together in a System Replication scenario. + For example, a ABAP and MESSAGESERVER applications. ## SAP system registration process The SAP system registration process has some caveats, so let's see them in more details. - As a main concept, the SAP system is uniquely identified by the database ID. This means that - there cannot exist any SAP system without a database, so Trento agents must be running + As a main concept, the SAP system is uniquely identified by the database ID plus application tenant. + This means that there cannot exist any SAP system without a database, so Trento agents must be running in those hosts in order to start the registration. That being said, this is the logical order of events in order to register a full system: - 1. A SAP system discovery message with a new database instance is received. - Database instances with Secondary role in a system replication scenario are discarded. - At this point, the registration process starts and the database is registered. - Any application instance discovery message without an associated database is ignored. - 2. New database instances/updates coming from already registered database instances are registered/applied. - 3. When a SAP system discovery with a new application instance is received, and the database associated to + 1. A database aggregate containing the tenant for this application must be already registered (check the database aggregate). + 2. When a SAP system discovery with a new application instance is received, and the database associated to this application exists: - Instances that are not MESSAGESERVER or ABAP will be added without completing a SAP system registration - To have a fully registered SAP system, a MESSAGESERVER instance and one ABAP instance are required - 4. New application instances/updates coming from already registered application instances are registered/applied. + 3. New application instances/updates coming from already registered application instances are registered/applied. - Find additional information about the application/database association in `Trento.SapSystems.Commands.RegisterApplicationInstance`. + Find additional information about the application association in `Trento.SapSystems.Commands.RegisterApplicationInstance`. """ require Trento.SapSystems.Enums.EnsaVersion, as: EnsaVersion @@ -49,21 +41,15 @@ defmodule Trento.SapSystems.SapSystem do alias Commanded.Aggregate.Multi - alias Trento.SapSystems.SapSystem - alias Trento.SapSystems.{ - Application, - Database, - Instance + Instance, + SapSystem } alias Trento.SapSystems.Commands.{ DeregisterApplicationInstance, - DeregisterDatabaseInstance, MarkApplicationInstanceAbsent, - MarkDatabaseInstanceAbsent, RegisterApplicationInstance, - RegisterDatabaseInstance, RollUpSapSystem } @@ -74,16 +60,6 @@ defmodule Trento.SapSystems.SapSystem do ApplicationInstanceMarkedPresent, ApplicationInstanceMoved, ApplicationInstanceRegistered, - DatabaseDeregistered, - DatabaseHealthChanged, - DatabaseInstanceDeregistered, - DatabaseInstanceHealthChanged, - DatabaseInstanceMarkedAbsent, - DatabaseInstanceMarkedPresent, - DatabaseInstanceRegistered, - DatabaseInstanceSystemReplicationChanged, - DatabaseRegistered, - DatabaseRestored, SapSystemDeregistered, SapSystemHealthChanged, SapSystemRegistered, @@ -104,152 +80,17 @@ defmodule Trento.SapSystems.SapSystem do field :sap_system_id, Ecto.UUID field :sid, :string, default: nil field :health, Ecto.Enum, values: Health.values() + # field :tenant, :string field :ensa_version, Ecto.Enum, values: EnsaVersion.values(), default: EnsaVersion.no_ensa() field :rolling_up, :boolean, default: false field :deregistered_at, :utc_datetime_usec, default: nil - embeds_one :database, Database - embeds_one :application, Application + embeds_many :instances, Instance end # Stop everything during the rollup process def execute(%SapSystem{rolling_up: true}, _), do: {:error, :sap_system_rolling_up} - def execute( - %SapSystem{sap_system_id: nil}, - %RegisterDatabaseInstance{ - system_replication: "Secondary" - } - ), - do: {:error, :sap_system_not_registered} - - # First time that a Database instance is registered, the SAP System starts its registration process. - # Database instances are accepted when the system replication is disabled or when enabled, only if the database - # has a primary role - # When an Application is discovered, the SAP System completes the registration process. - def execute( - %SapSystem{sap_system_id: nil}, - %RegisterDatabaseInstance{ - sap_system_id: sap_system_id, - sid: sid, - tenant: tenant, - host_id: host_id, - instance_number: instance_number, - instance_hostname: instance_hostname, - features: features, - http_port: http_port, - https_port: https_port, - start_priority: start_priority, - system_replication: system_replication, - system_replication_status: system_replication_status, - health: health - } - ) do - [ - %DatabaseRegistered{ - sap_system_id: sap_system_id, - sid: sid, - health: health - }, - %DatabaseInstanceRegistered{ - sap_system_id: sap_system_id, - sid: sid, - tenant: tenant, - instance_number: instance_number, - instance_hostname: instance_hostname, - features: features, - http_port: http_port, - https_port: https_port, - start_priority: start_priority, - host_id: host_id, - system_replication: system_replication, - system_replication_status: system_replication_status, - health: health - } - ] - end - - # Database restore - def execute( - %SapSystem{database: %Database{deregistered_at: deregistered_at}}, - %RegisterDatabaseInstance{ - system_replication: "Secondary" - } - ) - when not is_nil(deregistered_at), - do: {:error, :sap_system_not_registered} - - # When a deregistered database is present, we add the new database instance - # and restore the database, the conditions are the same as registration - def execute( - %SapSystem{database: %Database{deregistered_at: deregistered_at}}, - %RegisterDatabaseInstance{ - sap_system_id: sap_system_id, - sid: sid, - tenant: tenant, - host_id: host_id, - instance_number: instance_number, - instance_hostname: instance_hostname, - features: features, - http_port: http_port, - https_port: https_port, - start_priority: start_priority, - system_replication: system_replication, - system_replication_status: system_replication_status, - health: health - } - ) - when not is_nil(deregistered_at) do - [ - %DatabaseInstanceRegistered{ - sap_system_id: sap_system_id, - sid: sid, - tenant: tenant, - instance_number: instance_number, - instance_hostname: instance_hostname, - features: features, - http_port: http_port, - https_port: https_port, - start_priority: start_priority, - host_id: host_id, - system_replication: system_replication, - system_replication_status: system_replication_status, - health: health - }, - %DatabaseRestored{ - sap_system_id: sap_system_id, - health: health - } - ] - end - - # When a RegisterDatabaseInstance command is received by an existing SAP System aggregate, - # the SAP System aggregate registers the Database instance if it is not already registered - # and updates the health when needed. - def execute( - %SapSystem{database: %Database{instances: instances}} = sap_system, - %RegisterDatabaseInstance{host_id: host_id, instance_number: instance_number} = command - ) do - instance = get_instance(instances, host_id, instance_number) - - sap_system - |> Multi.new() - |> Multi.execute(fn _ -> - maybe_emit_database_instance_system_replication_changed_event(instance, command) - end) - |> Multi.execute(fn _ -> - maybe_emit_database_instance_health_changed_event(instance, command) - end) - |> Multi.execute(fn _ -> - maybe_emit_database_instance_registered_event(instance, command) - end) - |> Multi.execute(fn _ -> - maybe_emit_database_instance_marked_present_event(instance, command) - end) - |> Multi.execute(&maybe_emit_database_health_changed_event/1) - |> Multi.execute(&maybe_emit_sap_system_health_changed_event/1) - end - # Restore sap system # Same registration rules def execute( @@ -316,29 +157,7 @@ defmodule Trento.SapSystems.SapSystem do end def execute( - %SapSystem{sap_system_id: sap_system_id, database: %Database{instances: instances}}, - %MarkDatabaseInstanceAbsent{ - instance_number: instance_number, - host_id: host_id, - absent_at: absent_at - } - ) do - case get_instance(instances, host_id, instance_number) do - %Instance{absent_at: nil} -> - %DatabaseInstanceMarkedAbsent{ - instance_number: instance_number, - host_id: host_id, - sap_system_id: sap_system_id, - absent_at: absent_at - } - - _ -> - nil - end - end - - def execute( - %SapSystem{sap_system_id: sap_system_id, application: %Application{instances: instances}}, + %SapSystem{sap_system_id: sap_system_id, instances: instances}, %MarkApplicationInstanceAbsent{ instance_number: instance_number, host_id: host_id, @@ -359,29 +178,6 @@ defmodule Trento.SapSystems.SapSystem do end end - # Deregister a database instance and emit a DatabaseInstanceDeregistered - # also potentially emit SapSystemDeregistered and DatabaseDeregistered events - def execute( - %SapSystem{sap_system_id: sap_system_id} = sap_system, - %DeregisterDatabaseInstance{ - sap_system_id: sap_system_id, - deregistered_at: deregistered_at - } = instance - ) do - sap_system - |> Multi.new() - |> Multi.execute(fn _ -> - maybe_emit_database_instance_deregistered_event(sap_system, instance) - end) - |> Multi.execute(fn sap_system -> - maybe_emit_database_deregistered_event(sap_system, deregistered_at) - end) - |> Multi.execute(fn sap_system -> - maybe_emit_sap_system_deregistered_event(sap_system, deregistered_at) - end) - |> Multi.execute(&maybe_emit_sap_system_tombstoned_event/1) - end - # Deregister an application instance and emit a ApplicationInstanceDeregistered # also emit SapSystemDeregistered event if this was the last application instance def execute( @@ -426,117 +222,9 @@ defmodule Trento.SapSystems.SapSystem do end def apply( - %SapSystem{sap_system_id: nil}, - %DatabaseRegistered{ - sap_system_id: sap_system_id, - sid: sid, - health: health - } - ) do - %SapSystem{ - sap_system_id: sap_system_id, - database: %Database{ - sid: sid, - health: health - } - } - end - - def apply( - %SapSystem{database: %Database{instances: instances} = database} = sap_system, - %DatabaseInstanceRegistered{ - sid: sid, - system_replication: system_replication, - system_replication_status: system_replication_status, - instance_number: instance_number, - features: features, - host_id: host_id, - health: health - } - ) do - instances = [ - %Instance{ - sid: sid, - system_replication: system_replication, - system_replication_status: system_replication_status, - instance_number: instance_number, - features: features, - host_id: host_id, - health: health, - absent_at: nil - } - | instances - ] - - %SapSystem{ - sap_system - | database: Map.put(database, :instances, instances) - } - end - - def apply( - %SapSystem{database: %Database{instances: instances} = database} = sap_system, - %DatabaseInstanceSystemReplicationChanged{ - host_id: host_id, - instance_number: instance_number, - system_replication: system_replication, - system_replication_status: system_replication_status - } - ) do - instances = - Enum.map( - instances, - fn - %Instance{host_id: ^host_id, instance_number: ^instance_number} = instance -> - %Instance{ - instance - | system_replication: system_replication, - system_replication_status: system_replication_status - } - - instance -> - instance - end - ) - - %SapSystem{sap_system | database: Map.put(database, :instances, instances)} - end - - def apply( - %SapSystem{database: %Database{instances: instances} = database} = sap_system, - %DatabaseInstanceHealthChanged{ - host_id: host_id, - instance_number: instance_number, - health: health - } - ) do - instances = - Enum.map( - instances, - fn - %Instance{host_id: ^host_id, instance_number: ^instance_number} = instance -> - %Instance{instance | health: health} - - instance -> - instance - end - ) - - %SapSystem{sap_system | database: Map.put(database, :instances, instances)} - end - - def apply(%SapSystem{database: %Database{} = database} = sap_system, %DatabaseHealthChanged{ - health: health - }) do - %SapSystem{ - sap_system - | database: Map.put(database, :health, health) - } - end - - def apply( - %SapSystem{application: nil} = sap_system, + %SapSystem{instances: []} = sap_system, %ApplicationInstanceRegistered{ + sap_system_id: sap_system_id, sid: sid, instance_number: instance_number, features: features, @@ -544,28 +232,24 @@ defmodule Trento.SapSystems.SapSystem do health: health } ) do - application = %Application{ - sid: sid, - instances: [ - %Instance{ - sid: sid, - instance_number: instance_number, - features: features, - host_id: host_id, - health: health, - absent_at: nil - } - ] - } - %SapSystem{ sap_system - | application: application + | sap_system_id: sap_system_id, + instances: [ + %Instance{ + sid: sid, + instance_number: instance_number, + features: features, + host_id: host_id, + health: health, + absent_at: nil + } + ] } end def apply( - %SapSystem{application: %Application{instances: instances} = application} = sap_system, + %SapSystem{instances: instances} = sap_system, %ApplicationInstanceRegistered{ sid: sid, instance_number: instance_number, @@ -586,14 +270,11 @@ defmodule Trento.SapSystems.SapSystem do | instances ] - %SapSystem{ - sap_system - | application: Map.put(application, :instances, instances) - } + %SapSystem{sap_system | instances: instances} end def apply( - %SapSystem{application: %Application{instances: instances} = application} = sap_system, + %SapSystem{instances: instances} = sap_system, %ApplicationInstanceMoved{ instance_number: instance_number, old_host_id: old_host_id, @@ -612,14 +293,11 @@ defmodule Trento.SapSystems.SapSystem do instance end) - %SapSystem{ - sap_system - | application: Map.put(application, :instances, instances) - } + %SapSystem{sap_system | instances: instances} end def apply( - %SapSystem{application: %Application{instances: instances} = application} = sap_system, + %SapSystem{instances: instances} = sap_system, %ApplicationInstanceHealthChanged{ host_id: host_id, instance_number: instance_number, @@ -638,17 +316,19 @@ defmodule Trento.SapSystems.SapSystem do end ) - %SapSystem{sap_system | application: Map.put(application, :instances, instances)} + %SapSystem{sap_system | instances: instances} end def apply(%SapSystem{} = sap_system, %SapSystemRegistered{ + sap_system_id: sap_system_id, sid: sid, health: health, ensa_version: ensa_version }) do %SapSystem{ sap_system - | sid: sid, + | sap_system_id: sap_system_id, + sid: sid, health: health, ensa_version: ensa_version } @@ -683,25 +363,7 @@ defmodule Trento.SapSystems.SapSystem do end def apply( - %SapSystem{database: %Database{instances: instances} = database} = sap_system, - %DatabaseInstanceMarkedPresent{ - instance_number: instance_number, - host_id: host_id - } - ) do - instances = update_instance(instances, instance_number, host_id, %{absent_at: nil}) - - %SapSystem{ - sap_system - | database: %Database{ - database - | instances: instances - } - } - end - - def apply( - %SapSystem{application: %Application{instances: instances} = application} = sap_system, + %SapSystem{instances: instances} = sap_system, %ApplicationInstanceMarkedPresent{ instance_number: instance_number, host_id: host_id @@ -709,36 +371,11 @@ defmodule Trento.SapSystems.SapSystem do ) do instances = update_instance(instances, instance_number, host_id, %{absent_at: nil}) - %SapSystem{ - sap_system - | application: %Application{ - application - | instances: instances - } - } + %SapSystem{sap_system | instances: instances} end def apply( - %SapSystem{database: %Database{instances: instances} = database} = sap_system, - %DatabaseInstanceMarkedAbsent{ - instance_number: instance_number, - host_id: host_id, - absent_at: absent_at - } - ) do - instances = update_instance(instances, instance_number, host_id, %{absent_at: absent_at}) - - %SapSystem{ - sap_system - | database: %Database{ - database - | instances: instances - } - } - end - - def apply( - %SapSystem{application: %Application{instances: instances} = application} = sap_system, + %SapSystem{instances: instances} = sap_system, %ApplicationInstanceMarkedAbsent{ instance_number: instance_number, host_id: host_id, @@ -747,42 +384,11 @@ defmodule Trento.SapSystems.SapSystem do ) do instances = update_instance(instances, instance_number, host_id, %{absent_at: absent_at}) - %SapSystem{ - sap_system - | application: %Application{ - application - | instances: instances - } - } - end - - def apply( - %SapSystem{database: %Database{instances: instances} = database} = sap_system, - %DatabaseInstanceDeregistered{ - instance_number: instance_number, - host_id: host_id - } - ) do - instances = - Enum.reject(instances, fn - %Instance{instance_number: ^instance_number, host_id: ^host_id} -> - true - - _ -> - false - end) - - %SapSystem{ - sap_system - | database: %Database{ - database - | instances: instances - } - } + %SapSystem{sap_system | instances: instances} end def apply( - %SapSystem{application: %Application{instances: instances} = application} = sap_system, + %SapSystem{instances: instances} = sap_system, %ApplicationInstanceDeregistered{instance_number: instance_number, host_id: host_id} ) do instances = @@ -794,39 +400,7 @@ defmodule Trento.SapSystems.SapSystem do false end) - %SapSystem{ - sap_system - | application: %Application{ - application - | instances: instances - } - } - end - - def apply( - %SapSystem{database: database} = sap_system, - %DatabaseDeregistered{deregistered_at: deregistered_at} - ) do - %SapSystem{ - sap_system - | database: Map.put(database, :deregistered_at, deregistered_at) - } - end - - def apply( - %SapSystem{database: database} = sap_system, - %DatabaseRestored{ - health: health - } - ) do - %SapSystem{ - sap_system - | database: %Database{ - database - | health: health, - deregistered_at: nil - } - } + %SapSystem{sap_system | instances: instances} end def apply( @@ -853,134 +427,8 @@ defmodule Trento.SapSystems.SapSystem do def apply(%SapSystem{} = sap_system, %SapSystemTombstoned{}), do: sap_system - defp maybe_emit_database_instance_registered_event( - nil, - %RegisterDatabaseInstance{ - sap_system_id: sap_system_id, - sid: sid, - tenant: tenant, - instance_number: instance_number, - instance_hostname: instance_hostname, - features: features, - http_port: http_port, - https_port: https_port, - start_priority: start_priority, - host_id: host_id, - system_replication: system_replication, - system_replication_status: system_replication_status, - health: health - } - ) do - %DatabaseInstanceRegistered{ - sap_system_id: sap_system_id, - sid: sid, - tenant: tenant, - instance_number: instance_number, - instance_hostname: instance_hostname, - features: features, - http_port: http_port, - https_port: https_port, - start_priority: start_priority, - host_id: host_id, - system_replication: system_replication, - system_replication_status: system_replication_status, - health: health - } - end - - defp maybe_emit_database_instance_registered_event(_, _), do: nil - - defp maybe_emit_database_instance_marked_present_event( - %Instance{absent_at: nil}, - %RegisterDatabaseInstance{} - ), - do: nil - - defp maybe_emit_database_instance_marked_present_event( - %Instance{ - instance_number: instance_number, - host_id: host_id - }, - %RegisterDatabaseInstance{sap_system_id: sap_system_id} - ) do - %DatabaseInstanceMarkedPresent{ - instance_number: instance_number, - host_id: host_id, - sap_system_id: sap_system_id - } - end - - defp maybe_emit_database_instance_marked_present_event(_, _), do: nil - - defp maybe_emit_database_instance_system_replication_changed_event( - %Instance{ - system_replication: system_replication, - system_replication_status: system_replication_status - }, - %RegisterDatabaseInstance{ - sap_system_id: sap_system_id, - host_id: host_id, - instance_number: instance_number, - system_replication: new_system_replication, - system_replication_status: new_system_replication_status - } - ) - when system_replication != new_system_replication or - system_replication_status != new_system_replication_status do - %DatabaseInstanceSystemReplicationChanged{ - sap_system_id: sap_system_id, - host_id: host_id, - instance_number: instance_number, - system_replication: new_system_replication, - system_replication_status: new_system_replication_status - } - end - - defp maybe_emit_database_instance_system_replication_changed_event(_, _), do: nil - - defp maybe_emit_database_instance_health_changed_event( - %Instance{ - health: health - }, - %RegisterDatabaseInstance{ - sap_system_id: sap_system_id, - host_id: host_id, - instance_number: instance_number, - health: new_health - } - ) - when health != new_health do - %DatabaseInstanceHealthChanged{ - sap_system_id: sap_system_id, - host_id: host_id, - instance_number: instance_number, - health: new_health - } - end - - defp maybe_emit_database_instance_health_changed_event(_, _), do: nil - - # Returns a DatabaseHealthChanged event if the newly computed aggregated health of all the instances - # is different from the previous Database health. - defp maybe_emit_database_health_changed_event(%SapSystem{ - sap_system_id: sap_system_id, - database: %Database{instances: instances, health: health} - }) do - new_health = - instances - |> Enum.map(& &1.health) - |> HealthService.compute_aggregated_health() - - if new_health != health do - %DatabaseHealthChanged{ - sap_system_id: sap_system_id, - health: new_health - } - end - end - defp maybe_emit_application_instance_registered_or_moved_event( - %SapSystem{application: nil}, + %SapSystem{instances: []}, %RegisterApplicationInstance{ sap_system_id: sap_system_id, sid: sid, @@ -1009,7 +457,7 @@ defmodule Trento.SapSystems.SapSystem do end defp maybe_emit_application_instance_registered_or_moved_event( - %SapSystem{application: %Application{instances: instances}}, + %SapSystem{instances: instances}, %RegisterApplicationInstance{ sap_system_id: sap_system_id, sid: sid, @@ -1067,7 +515,7 @@ defmodule Trento.SapSystems.SapSystem do defp maybe_emit_application_instance_marked_present_event( %SapSystem{ sap_system_id: sap_system_id, - application: %Application{instances: instances} + instances: instances }, %RegisterApplicationInstance{ instance_number: instance_number, @@ -1093,7 +541,7 @@ defmodule Trento.SapSystems.SapSystem do defp maybe_emit_application_instance_marked_present_event(_, _), do: nil defp maybe_emit_application_instance_health_changed_event( - %SapSystem{application: %Application{instances: instances}}, + %SapSystem{instances: instances}, %RegisterApplicationInstance{ sap_system_id: sap_system_id, instance_number: instance_number, @@ -1113,12 +561,9 @@ defmodule Trento.SapSystems.SapSystem do end end - # Restore a SAP system when the database is registered + # Restore a SAP system when the all the requires instances are registered defp maybe_emit_sap_system_restored_event( - %SapSystem{ - application: %Application{instances: instances}, - database: %Database{deregistered_at: nil} - }, + %SapSystem{instances: instances}, %RegisterApplicationInstance{ sap_system_id: sap_system_id, tenant: tenant, @@ -1136,11 +581,8 @@ defmodule Trento.SapSystems.SapSystem do end end - # Do not restore SAP system if the database is not registered - defp maybe_emit_sap_system_restored_event(%SapSystem{}, %RegisterApplicationInstance{}), do: nil - defp maybe_emit_sap_system_registered_or_updated_event( - %SapSystem{sid: nil, application: %Application{instances: instances}}, + %SapSystem{sid: nil, instances: instances}, %RegisterApplicationInstance{ sap_system_id: sap_system_id, sid: sid, @@ -1191,7 +633,7 @@ defmodule Trento.SapSystems.SapSystem do do: %SapSystemUpdated{sap_system_id: sap_system_id, ensa_version: ensa_version} # Do not emit health changed event as the SAP system is not completely registered yet - defp maybe_emit_sap_system_health_changed_event(%SapSystem{application: nil}), do: nil + defp maybe_emit_sap_system_health_changed_event(%SapSystem{instances: []}), do: nil defp maybe_emit_sap_system_health_changed_event(%SapSystem{sid: nil}), do: nil # Returns a SapSystemHealthChanged event when the aggregated health of the application instances @@ -1199,13 +641,11 @@ defmodule Trento.SapSystems.SapSystem do defp maybe_emit_sap_system_health_changed_event(%SapSystem{ sap_system_id: sap_system_id, health: health, - application: %Application{instances: instances}, - database: %Database{health: database_health} + instances: instances }) do new_health = instances |> Enum.map(& &1.health) - |> Kernel.++([database_health]) |> HealthService.compute_aggregated_health() if new_health != health do @@ -1216,55 +656,14 @@ defmodule Trento.SapSystems.SapSystem do end end - defp maybe_emit_database_instance_deregistered_event( - %SapSystem{database: nil}, - %DeregisterDatabaseInstance{} - ), - do: {:error, :database_instance_not_registered} - - defp maybe_emit_database_instance_deregistered_event( - %SapSystem{database: %Database{instances: []}}, - %DeregisterDatabaseInstance{} - ), - do: {:error, :database_instance_not_registered} - - defp maybe_emit_database_instance_deregistered_event( - %SapSystem{database: %Database{instances: instances}}, - %DeregisterDatabaseInstance{ - sap_system_id: sap_system_id, - host_id: host_id, - instance_number: instance_number, - deregistered_at: deregistered_at - } - ) do - case get_instance(instances, host_id, instance_number) do - nil -> - {:error, :database_instance_not_registered} - - _ -> - %DatabaseInstanceDeregistered{ - sap_system_id: sap_system_id, - instance_number: instance_number, - host_id: host_id, - deregistered_at: deregistered_at - } - end - end - defp maybe_emit_application_instance_deregistered_event( - %SapSystem{application: nil}, + %SapSystem{instances: []}, %DeregisterApplicationInstance{} ), do: {:error, :application_instance_not_registered} defp maybe_emit_application_instance_deregistered_event( - %SapSystem{application: %Application{instances: []}}, - %DeregisterApplicationInstance{} - ), - do: {:error, :application_instance_not_registered} - - defp maybe_emit_application_instance_deregistered_event( - %SapSystem{application: %Application{instances: instances}}, + %SapSystem{instances: instances}, %DeregisterApplicationInstance{ sap_system_id: sap_system_id, host_id: host_id, @@ -1296,21 +695,7 @@ defmodule Trento.SapSystems.SapSystem do %SapSystem{ sap_system_id: sap_system_id, deregistered_at: nil, - database: %Database{deregistered_at: database_deregistered_at} - }, - deregistered_at - ) - when not is_nil(database_deregistered_at) do - %SapSystemDeregistered{sap_system_id: sap_system_id, deregistered_at: deregistered_at} - end - - defp maybe_emit_sap_system_deregistered_event( - %SapSystem{ - sap_system_id: sap_system_id, - deregistered_at: nil, - application: %Application{ - instances: instances - } + instances: instances }, deregistered_at ) do @@ -1323,61 +708,13 @@ defmodule Trento.SapSystems.SapSystem do defp maybe_emit_sap_system_tombstoned_event(%SapSystem{ sap_system_id: sap_system_id, - application: %Application{ - instances: [] - }, - database: %Database{ - instances: [] - } + instances: [] }) do %SapSystemTombstoned{sap_system_id: sap_system_id} end defp maybe_emit_sap_system_tombstoned_event(_), do: nil - defp maybe_emit_database_deregistered_event( - %SapSystem{ - sap_system_id: sap_system_id, - database: %Database{ - deregistered_at: nil, - instances: [] - } - }, - deregistered_at - ) do - %DatabaseDeregistered{sap_system_id: sap_system_id, deregistered_at: deregistered_at} - end - - defp maybe_emit_database_deregistered_event( - %SapSystem{ - sap_system_id: sap_system_id, - database: %Database{ - instances: instances, - deregistered_at: nil - } - }, - deregistered_at - ) do - has_primary? = - Enum.any?(instances, fn %{system_replication: system_replication} -> - system_replication == "Primary" - end) - - has_secondary? = - Enum.any?(instances, fn %{system_replication: system_replication} -> - system_replication == "Secondary" - end) - - if has_secondary? and !has_primary? do - %DatabaseDeregistered{ - sap_system_id: sap_system_id, - deregistered_at: deregistered_at - } - end - end - - defp maybe_emit_database_deregistered_event(_, _), do: nil - defp instances_have_abap?(instances) do Enum.any?(instances, fn %{features: features} -> features =~ "ABAP" end) end diff --git a/test/e2e/cypress/e2e/sap_systems_overview.cy.js b/test/e2e/cypress/e2e/sap_systems_overview.cy.js index 5aa5c84960..feacf75717 100644 --- a/test/e2e/cypress/e2e/sap_systems_overview.cy.js +++ b/test/e2e/cypress/e2e/sap_systems_overview.cy.js @@ -295,7 +295,7 @@ context('SAP Systems Overview', () => { describe('Move application instance', () => { const nwdSystem = { sid: 'NWD', - id: 'f534a4ad-cef7-5234-b196-e67082ffb50c', + id: '67b247e4-ab5b-5094-993a-a4fd70d0e8d1', hostId: '9a3ec76a-dd4f-5013-9cf0-5eb4cf89898f', instanceNumber: '02', hostname: 'vmnwdev01', diff --git a/test/e2e/cypress/fixtures/sap-system-details/selected_system.js b/test/e2e/cypress/fixtures/sap-system-details/selected_system.js index 80f1b08b9e..4cd5085359 100644 --- a/test/e2e/cypress/fixtures/sap-system-details/selected_system.js +++ b/test/e2e/cypress/fixtures/sap-system-details/selected_system.js @@ -6,7 +6,7 @@ export const healthMap = { }; export const selectedSystem = { - Id: 'f534a4ad-cef7-5234-b196-e67082ffb50c', + Id: '67b247e4-ab5b-5094-993a-a4fd70d0e8d1', Sid: 'NWD', Type: 'Application server', Hosts: [ diff --git a/test/e2e/cypress/fixtures/sap-systems-overview/available_sap_systems.js b/test/e2e/cypress/fixtures/sap-systems-overview/available_sap_systems.js index 15bb0d956f..7442054cfe 100644 --- a/test/e2e/cypress/fixtures/sap-systems-overview/available_sap_systems.js +++ b/test/e2e/cypress/fixtures/sap-systems-overview/available_sap_systems.js @@ -19,7 +19,7 @@ export const isHanaPrimary = (instance) => export const availableSAPSystems = [ { sid: 'NWD', - id: 'f534a4ad-cef7-5234-b196-e67082ffb50c', + id: '67b247e4-ab5b-5094-993a-a4fd70d0e8d1', health: 'GREEN', attachedDatabase: { sid: 'HDD', @@ -104,7 +104,7 @@ export const availableSAPSystems = [ tag: 'env3', }, { - id: '6c9208eb-a5bb-57ef-be5c-6422dedab602', + id: 'eb7bc03e-166f-5ed0-b22d-79672d110d04', sid: 'NWP', health: 'GREEN', attachedDatabase: { @@ -190,7 +190,7 @@ export const availableSAPSystems = [ tag: 'env1', }, { - id: 'cd52e571-c897-5bba-b0f9-e155ceca1fff', + id: '6748d2dd-b5a1-5599-895c-d1308b2d6541', sid: 'NWQ', health: 'GREEN', attachedDatabase: { diff --git a/test/support/factory.ex b/test/support/factory.ex index 04efda07a3..d05d9f8a60 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -69,12 +69,15 @@ defmodule Trento.Factory do alias Trento.SapSystems.Commands.{ DeregisterApplicationInstance, - DeregisterDatabaseInstance, RegisterApplicationInstance, - RegisterDatabaseInstance, RollUpSapSystem } + alias Trento.Databases.Commands.{ + DeregisterDatabaseInstance, + RegisterDatabaseInstance + } + alias Trento.Clusters.Commands.RegisterClusterHost alias Trento.Hosts.Projections.{ @@ -332,7 +335,7 @@ defmodule Trento.Factory do def deregister_database_instance_command_factory do DeregisterDatabaseInstance.new!(%{ - sap_system_id: Faker.UUID.v4(), + database_id: Faker.UUID.v4(), deregistered_at: DateTime.utc_now(), host_id: Faker.UUID.v4(), instance_number: "00" @@ -633,7 +636,7 @@ defmodule Trento.Factory do def register_database_instance_command_factory do RegisterDatabaseInstance.new!(%{ - sap_system_id: Faker.UUID.v4(), + database_id: Faker.UUID.v4(), sid: Faker.StarWars.planet(), tenant: Faker.Beer.hop(), instance_number: "00", diff --git a/test/trento/databases/database_test.exs b/test/trento/databases/database_test.exs new file mode 100644 index 0000000000..eb6cbd8ea8 --- /dev/null +++ b/test/trento/databases/database_test.exs @@ -0,0 +1,1755 @@ +defmodule Trento.Databases.DatabaseTest do + use Trento.AggregateCase, aggregate: Trento.Databases.Database, async: true + + import Trento.Factory + + alias Trento.Databases.Commands.{ + DeregisterDatabaseInstance, + MarkDatabaseInstanceAbsent, + RegisterDatabaseInstance + } + + alias Trento.SapSystems.Events.{ + DatabaseDeregistered, + DatabaseHealthChanged, + DatabaseInstanceDeregistered, + DatabaseInstanceHealthChanged, + DatabaseInstanceMarkedAbsent, + DatabaseInstanceMarkedPresent, + DatabaseInstanceRegistered, + DatabaseInstanceSystemReplicationChanged, + DatabaseRegistered, + DatabaseRestored + } + + alias Trento.Databases.Database + alias Trento.SapSystems.Instance + + describe "Database registration" do + test "should fail when a database does not exists and the database instance has Secondary role" do + command = + build(:register_database_instance_command, + system_replication: "Secondary" + ) + + assert_error( + command, + {:error, :database_not_registered} + ) + end + + test "should register a database when the system replication is disabled" do + database_id = Faker.UUID.v4() + sid = Faker.StarWars.planet() + tenant = Faker.Beer.style() + instance_number = "00" + instance_hostname = Faker.Airports.iata() + features = Faker.Pokemon.name() + http_port = 80 + https_port = 443 + start_priority = "0.9" + host_id = Faker.UUID.v4() + + assert_events_and_state( + [], + RegisterDatabaseInstance.new!(%{ + database_id: database_id, + sid: sid, + tenant: tenant, + instance_number: instance_number, + instance_hostname: instance_hostname, + features: features, + http_port: http_port, + https_port: https_port, + start_priority: start_priority, + host_id: host_id, + system_replication: nil, + health: :passing + }), + [ + %DatabaseRegistered{ + sap_system_id: database_id, + sid: sid, + health: :passing + }, + %DatabaseInstanceRegistered{ + sap_system_id: database_id, + sid: sid, + tenant: tenant, + instance_number: instance_number, + instance_hostname: instance_hostname, + features: features, + http_port: http_port, + https_port: https_port, + start_priority: start_priority, + host_id: host_id, + system_replication: nil, + system_replication_status: nil, + health: :passing + } + ], + %Database{ + database_id: database_id, + sid: sid, + health: :passing, + instances: [ + %Instance{ + sid: sid, + system_replication: nil, + system_replication_status: nil, + instance_number: instance_number, + features: features, + host_id: host_id, + health: :passing, + absent_at: nil + } + ] + } + ) + end + + test "should register a database when the system replication is enabled and the database role is primary" do + database_id = Faker.UUID.v4() + sid = Faker.StarWars.planet() + tenant = Faker.Beer.style() + instance_number = "00" + instance_hostname = Faker.Airports.iata() + features = Faker.Pokemon.name() + http_port = 80 + https_port = 443 + start_priority = "0.9" + host_id = Faker.UUID.v4() + + assert_events_and_state( + [], + RegisterDatabaseInstance.new!(%{ + database_id: database_id, + sid: sid, + tenant: tenant, + instance_number: instance_number, + instance_hostname: instance_hostname, + features: features, + http_port: http_port, + https_port: https_port, + start_priority: start_priority, + host_id: host_id, + system_replication: "Primary", + system_replication_status: "ACTIVE", + health: :passing + }), + [ + %DatabaseRegistered{ + sap_system_id: database_id, + sid: sid, + health: :passing + }, + %DatabaseInstanceRegistered{ + sap_system_id: database_id, + sid: sid, + tenant: tenant, + instance_number: instance_number, + instance_hostname: instance_hostname, + features: features, + http_port: http_port, + https_port: https_port, + start_priority: start_priority, + host_id: host_id, + system_replication: "Primary", + system_replication_status: "ACTIVE", + health: :passing + } + ], + %Database{ + database_id: database_id, + sid: sid, + health: :passing, + instances: [ + %Instance{ + sid: sid, + system_replication: "Primary", + system_replication_status: "ACTIVE", + instance_number: instance_number, + features: features, + host_id: host_id, + health: :passing + } + ] + } + ) + end + + test "should add a database instance to an existing Database" do + database_id = Faker.UUID.v4() + sid = Faker.StarWars.planet() + tenant = Faker.Beer.style() + instance_number = "00" + features = Faker.Pokemon.name() + host_id = Faker.UUID.v4() + + initial_events = [ + build( + :database_registered_event, + sap_system_id: database_id, + sid: sid + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + sid: sid, + tenant: tenant, + instance_number: "10" + ) + ] + + assert_events_and_state( + initial_events, + build( + :register_database_instance_command, + database_id: database_id, + sid: sid, + tenant: tenant, + instance_number: instance_number, + features: features, + host_id: host_id, + health: :passing + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + sid: sid, + tenant: tenant, + instance_number: instance_number, + features: features, + host_id: host_id, + health: :passing + ), + fn state -> + assert %Database{ + instances: [ + %Instance{ + sid: ^sid, + instance_number: ^instance_number, + features: ^features, + host_id: ^host_id, + health: :passing + } + | _ + ] + } = state + end + ) + end + + test "should not add a database instance if the database instance was already registered" do + database_registered_event = build(:database_registered_event) + + database_instance_registered_event = + build( + :database_instance_registered_event, + sap_system_id: database_registered_event.sap_system_id + ) + + initial_events = [ + database_registered_event, + database_instance_registered_event + ] + + assert_events( + initial_events, + build( + :register_database_instance_command, + database_id: database_registered_event.sap_system_id, + sid: database_instance_registered_event.sid, + tenant: database_instance_registered_event.tenant, + instance_number: database_instance_registered_event.instance_number, + features: database_instance_registered_event.features, + host_id: database_instance_registered_event.host_id, + system_replication: database_instance_registered_event.system_replication, + system_replication_status: database_instance_registered_event.system_replication_status, + health: :passing + ), + [] + ) + end + + test "should change the system replication of a database instance" do + database_registered_event = build(:database_registered_event) + + database_instance_registered_event = + build( + :database_instance_registered_event, + sap_system_id: database_registered_event.sap_system_id, + system_replication: "Secondary", + system_replication_status: "" + ) + + initial_events = [ + database_registered_event, + database_instance_registered_event + ] + + assert_events( + initial_events, + build( + :register_database_instance_command, + database_id: database_registered_event.sap_system_id, + sid: database_instance_registered_event.sid, + tenant: database_instance_registered_event.tenant, + instance_number: database_instance_registered_event.instance_number, + features: database_instance_registered_event.features, + host_id: database_instance_registered_event.host_id, + system_replication: "Primary", + system_replication_status: "ACTIVE", + health: :passing + ), + %DatabaseInstanceSystemReplicationChanged{ + sap_system_id: database_registered_event.sap_system_id, + host_id: database_instance_registered_event.host_id, + instance_number: database_instance_registered_event.instance_number, + system_replication: "Primary", + system_replication_status: "ACTIVE" + } + ) + end + end + + describe "Database health" do + test "should change the health of a Database when a new Database instance is registered" do + database_id = Faker.UUID.v4() + sid = Faker.StarWars.planet() + tenant = Faker.Beer.style() + instance_number = "00" + features = Faker.Pokemon.name() + host_id = Faker.UUID.v4() + + initial_events = [ + build(:database_registered_event, sap_system_id: database_id), + build(:database_instance_registered_event, sap_system_id: database_id) + ] + + assert_events_and_state( + initial_events, + build( + :register_database_instance_command, + database_id: database_id, + sid: sid, + tenant: tenant, + instance_number: instance_number, + features: features, + host_id: host_id, + health: :critical + ), + [ + build( + :database_instance_registered_event, + sap_system_id: database_id, + sid: sid, + tenant: tenant, + instance_number: instance_number, + features: features, + host_id: host_id, + health: :critical + ), + %DatabaseHealthChanged{ + sap_system_id: database_id, + health: :critical + } + ], + fn state -> + %Database{ + health: :critical, + instances: [ + %Instance{ + health: :critical + }, + %Instance{ + health: :passing + } + ] + } = state + end + ) + end + + test "should change the health of a Database when a Database instance has changed the health status" do + database_id = Faker.UUID.v4() + host_id = Faker.UUID.v4() + instance_number = "00" + + database_instance_registered_event = + build( + :database_instance_registered_event, + sap_system_id: database_id, + host_id: host_id, + instance_number: instance_number + ) + + initial_events = [ + build(:database_registered_event, sap_system_id: database_id), + database_instance_registered_event + ] + + assert_events_and_state( + initial_events, + build( + :register_database_instance_command, + database_id: database_id, + sid: database_instance_registered_event.sid, + tenant: database_instance_registered_event.tenant, + instance_number: instance_number, + features: database_instance_registered_event.features, + host_id: host_id, + health: :critical + ), + [ + %DatabaseInstanceHealthChanged{ + sap_system_id: database_id, + instance_number: instance_number, + host_id: host_id, + health: :critical + }, + %DatabaseHealthChanged{ + sap_system_id: database_id, + health: :critical + } + ], + fn state -> + assert %Database{ + health: :critical, + instances: [ + %Instance{ + instance_number: ^instance_number, + host_id: ^host_id, + health: :critical + } + ] + } = state + end + ) + end + + test "should not change the health of a Database if no instance has changed the health status" do + database_id = Faker.UUID.v4() + + new_instance_number = "20" + new_instance_features = Faker.Pokemon.name() + new_instance_host_id = Faker.UUID.v4() + + database_instance_registered_event = + build( + :database_instance_registered_event, + sap_system_id: database_id, + health: :warning + ) + + initial_events = [ + build(:database_registered_event, sap_system_id: database_id, health: :warning), + database_instance_registered_event + ] + + assert_events_and_state( + initial_events, + [ + build( + :register_database_instance_command, + database_id: database_id, + sid: database_instance_registered_event.sid, + tenant: database_instance_registered_event.tenant, + instance_number: database_instance_registered_event.instance_number, + features: database_instance_registered_event.features, + host_id: database_instance_registered_event.host_id, + health: :warning + ), + build( + :register_database_instance_command, + database_id: database_id, + sid: database_instance_registered_event.sid, + tenant: database_instance_registered_event.tenant, + instance_number: new_instance_number, + features: new_instance_features, + host_id: new_instance_host_id, + health: :warning + ) + ], + [ + build( + :database_instance_registered_event, + sap_system_id: database_id, + sid: database_instance_registered_event.sid, + tenant: database_instance_registered_event.tenant, + instance_number: new_instance_number, + features: new_instance_features, + host_id: new_instance_host_id, + health: :warning + ) + ], + fn state -> + assert %Database{ + health: :warning, + instances: [ + %Instance{ + health: :warning + }, + %Instance{ + health: :warning + } + ] + } = state + end + ) + end + end + + describe "deregistration" do + test "should not restore a deregistered database when the registering database instance has Secondary role" do + database_id = UUID.uuid4() + + primary_database_host_id = UUID.uuid4() + secondary_database_host_id = UUID.uuid4() + + deregistered_at = DateTime.utc_now() + + db_instance_number_1 = "00" + db_instance_number_2 = "01" + + db_sid = fake_sid() + + initial_events = [ + build( + :database_registered_event, + sap_system_id: database_id, + sid: db_sid + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + host_id: primary_database_host_id, + sid: db_sid, + instance_number: db_instance_number_1, + system_replication: "Primary" + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + host_id: secondary_database_host_id, + instance_number: db_instance_number_2, + system_replication: "Secondary", + sid: db_sid + ), + build(:database_instance_deregistered_event, + sap_system_id: database_id, + host_id: primary_database_host_id, + instance_number: db_instance_number_1, + deregistered_at: deregistered_at + ), + build(:database_deregistered_event, + sap_system_id: database_id, + deregistered_at: deregistered_at + ) + ] + + command = + build(:register_database_instance_command, + system_replication: "Secondary", + sid: db_sid, + database_id: database_id + ) + + assert_error( + initial_events, + command, + {:error, :database_not_registered} + ) + end + + test "should restore a deregistered database when the registering database instance has system replication disabled, with database instance leftovers" do + database_id = UUID.uuid4() + + primary_database_host_id = UUID.uuid4() + secondary_database_host_id = UUID.uuid4() + + deregistered_at = DateTime.utc_now() + + db_instance_number_1 = "00" + db_instance_number_2 = "01" + + db_sid = fake_sid() + + initial_events = [ + build( + :database_registered_event, + sap_system_id: database_id, + sid: db_sid + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + host_id: primary_database_host_id, + sid: db_sid, + instance_number: db_instance_number_1, + system_replication: "Primary" + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + host_id: secondary_database_host_id, + instance_number: db_instance_number_2, + system_replication: "Secondary", + sid: db_sid + ), + build(:database_instance_deregistered_event, + sap_system_id: database_id, + host_id: primary_database_host_id, + instance_number: db_instance_number_1, + deregistered_at: deregistered_at + ), + build(:database_deregistered_event, + sap_system_id: database_id, + deregistered_at: deregistered_at + ) + ] + + %{features: features, instance_number: instance_number, health: health} = + command = + build(:register_database_instance_command, + system_replication: nil, + sid: db_sid, + database_id: database_id + ) + + assert_events_and_state( + initial_events, + command, + [ + %DatabaseInstanceRegistered{ + sap_system_id: database_id, + sid: db_sid, + tenant: command.tenant, + instance_number: command.instance_number, + instance_hostname: command.instance_hostname, + features: command.features, + http_port: command.http_port, + https_port: command.https_port, + start_priority: command.start_priority, + host_id: command.host_id, + system_replication: command.system_replication, + system_replication_status: command.system_replication_status, + health: command.health + }, + %DatabaseRestored{ + sap_system_id: database_id, + health: command.health + } + ], + fn state -> + assert %Database{ + deregistered_at: nil, + sid: ^db_sid, + instances: [ + %Instance{ + sid: ^db_sid, + instance_number: ^instance_number, + features: ^features, + health: ^health + }, + %Instance{} + ] + } = state + end + ) + end + + test "should restore a deregistered database when the registering database instance has system replication disabled, without database instance leftovers" do + database_id = UUID.uuid4() + + primary_database_host_id = UUID.uuid4() + secondary_database_host_id = UUID.uuid4() + + deregistered_at = DateTime.utc_now() + + db_instance_number_1 = "00" + db_instance_number_2 = "01" + + db_sid = fake_sid() + + initial_events = [ + build( + :database_registered_event, + sap_system_id: database_id, + sid: db_sid + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + host_id: primary_database_host_id, + sid: db_sid, + instance_number: db_instance_number_1, + system_replication: "Primary" + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + host_id: secondary_database_host_id, + instance_number: db_instance_number_2, + system_replication: "Secondary", + sid: db_sid + ), + build(:database_instance_deregistered_event, + sap_system_id: database_id, + host_id: primary_database_host_id, + instance_number: db_instance_number_1, + deregistered_at: deregistered_at + ), + build(:database_instance_deregistered_event, + sap_system_id: database_id, + host_id: secondary_database_host_id, + instance_number: db_instance_number_2, + deregistered_at: deregistered_at + ), + build(:database_deregistered_event, + sap_system_id: database_id, + deregistered_at: deregistered_at + ) + ] + + %{features: features, instance_number: instance_number, health: health} = + command = + build(:register_database_instance_command, + system_replication: nil, + sid: db_sid, + database_id: database_id + ) + + assert_events_and_state( + initial_events, + command, + [ + %DatabaseInstanceRegistered{ + sap_system_id: database_id, + sid: db_sid, + tenant: command.tenant, + instance_number: command.instance_number, + instance_hostname: command.instance_hostname, + features: command.features, + http_port: command.http_port, + https_port: command.https_port, + start_priority: command.start_priority, + host_id: command.host_id, + system_replication: command.system_replication, + system_replication_status: command.system_replication_status, + health: command.health + }, + %DatabaseRestored{ + sap_system_id: database_id, + health: command.health + } + ], + fn state -> + assert Kernel.length(state.instances) == 1 + + assert %Database{ + deregistered_at: nil, + sid: ^db_sid, + instances: [ + %Instance{ + sid: ^db_sid, + instance_number: ^instance_number, + features: ^features, + health: ^health, + system_replication: nil + } + ] + } = state + end + ) + end + + test "should restore a deregistered database when the registering database instance is a primary, without database instance leftovers" do + database_id = UUID.uuid4() + + primary_database_host_id = UUID.uuid4() + secondary_database_host_id = UUID.uuid4() + + deregistered_at = DateTime.utc_now() + + db_instance_number_1 = "00" + db_instance_number_2 = "01" + + db_sid = fake_sid() + + initial_events = [ + build( + :database_registered_event, + sap_system_id: database_id, + sid: db_sid + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + host_id: primary_database_host_id, + sid: db_sid, + instance_number: db_instance_number_1, + system_replication: "Primary" + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + host_id: secondary_database_host_id, + instance_number: db_instance_number_2, + system_replication: "Secondary", + sid: db_sid + ), + build(:database_instance_deregistered_event, + sap_system_id: database_id, + host_id: primary_database_host_id, + instance_number: db_instance_number_1, + deregistered_at: deregistered_at + ), + build(:database_instance_deregistered_event, + sap_system_id: database_id, + host_id: secondary_database_host_id, + instance_number: db_instance_number_2, + deregistered_at: deregistered_at + ), + build(:database_deregistered_event, + sap_system_id: database_id, + deregistered_at: deregistered_at + ) + ] + + %{features: features, instance_number: instance_number, health: health} = + command = + build(:register_database_instance_command, + system_replication: "Primary", + sid: db_sid, + database_id: database_id + ) + + assert_events_and_state( + initial_events, + command, + [ + %DatabaseInstanceRegistered{ + sap_system_id: database_id, + sid: db_sid, + tenant: command.tenant, + instance_number: command.instance_number, + instance_hostname: command.instance_hostname, + features: command.features, + http_port: command.http_port, + https_port: command.https_port, + start_priority: command.start_priority, + host_id: command.host_id, + system_replication: command.system_replication, + system_replication_status: command.system_replication_status, + health: command.health + }, + %DatabaseRestored{ + sap_system_id: database_id, + health: command.health + } + ], + fn state -> + assert Kernel.length(state.instances) == 1 + + assert %Database{ + deregistered_at: nil, + sid: ^db_sid, + instances: [ + %Instance{ + sid: ^db_sid, + instance_number: ^instance_number, + features: ^features, + health: ^health, + system_replication: "Primary" + } + ] + } = state + end + ) + end + + test "should restore a deregistered database when the registering database instance is a primary, with database instance leftovers" do + database_id = UUID.uuid4() + + primary_database_host_id = UUID.uuid4() + secondary_database_host_id = UUID.uuid4() + + deregistered_at = DateTime.utc_now() + + db_instance_number_1 = "00" + db_instance_number_2 = "01" + + db_sid = fake_sid() + + initial_events = [ + build( + :database_registered_event, + sap_system_id: database_id, + sid: db_sid + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + host_id: primary_database_host_id, + sid: db_sid, + instance_number: db_instance_number_1, + system_replication: "Primary" + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + host_id: secondary_database_host_id, + instance_number: db_instance_number_2, + system_replication: "Secondary", + sid: db_sid + ), + build(:database_instance_deregistered_event, + sap_system_id: database_id, + host_id: primary_database_host_id, + instance_number: db_instance_number_1, + deregistered_at: deregistered_at + ), + build(:database_deregistered_event, + sap_system_id: database_id, + deregistered_at: deregistered_at + ) + ] + + %{features: features, instance_number: instance_number, health: health} = + command = + build(:register_database_instance_command, + system_replication: "Primary", + sid: db_sid, + database_id: database_id + ) + + assert_events_and_state( + initial_events, + command, + [ + %DatabaseInstanceRegistered{ + sap_system_id: database_id, + sid: db_sid, + tenant: command.tenant, + instance_number: command.instance_number, + instance_hostname: command.instance_hostname, + features: command.features, + http_port: command.http_port, + https_port: command.https_port, + start_priority: command.start_priority, + host_id: command.host_id, + system_replication: command.system_replication, + system_replication_status: command.system_replication_status, + health: command.health + }, + %DatabaseRestored{ + sap_system_id: database_id, + health: command.health + } + ], + fn state -> + assert Kernel.length(state.instances) == 2 + + assert %Database{ + deregistered_at: nil, + sid: ^db_sid, + instances: [ + %Instance{ + sid: ^db_sid, + instance_number: ^instance_number, + features: ^features, + health: ^health, + system_replication: "Primary" + }, + %Instance{} + ] + } = state + end + ) + end + + test "should reject all the commands except for the registration/instance deregistration ones, when the Database is deregistered" do + database_id = UUID.uuid4() + + primary_database_host_id = UUID.uuid4() + secondary_database_host_id = UUID.uuid4() + + deregistered_at = DateTime.utc_now() + + db_instance_number_1 = "00" + db_instance_number_2 = "01" + + db_sid = fake_sid() + + initial_events = [ + build( + :database_registered_event, + sap_system_id: database_id, + sid: db_sid + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + host_id: primary_database_host_id, + sid: db_sid, + instance_number: db_instance_number_1, + system_replication: "Primary" + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + host_id: secondary_database_host_id, + instance_number: db_instance_number_2, + system_replication: "Secondary", + sid: db_sid + ), + build(:database_instance_deregistered_event, + sap_system_id: database_id, + host_id: primary_database_host_id, + instance_number: db_instance_number_1, + deregistered_at: deregistered_at + ), + build(:database_deregistered_event, + sap_system_id: database_id, + deregistered_at: deregistered_at + ) + ] + + commands_to_accept = [ + build(:register_database_instance_command) + ] + + for command <- commands_to_accept do + assert match?({:ok, _, _}, aggregate_run(initial_events, command)), + "Command #{inspect(command)} should be accepted by a deregistered SAP system" + end + end + + test "should deregister a Database when the Primary database instance is removed" do + database_id = UUID.uuid4() + + primary_database_host_id = UUID.uuid4() + secondary_database_host_id = UUID.uuid4() + + deregistered_at = DateTime.utc_now() + + db_instance_number_1 = "00" + db_instance_number_2 = "01" + + db_sid = fake_sid() + + assert_events_and_state( + [ + build( + :database_registered_event, + sap_system_id: database_id, + sid: db_sid + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + host_id: primary_database_host_id, + sid: db_sid, + instance_number: db_instance_number_1, + system_replication: "Primary" + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + host_id: secondary_database_host_id, + instance_number: db_instance_number_2, + system_replication: "Secondary", + sid: db_sid + ) + ], + %DeregisterDatabaseInstance{ + database_id: database_id, + host_id: primary_database_host_id, + instance_number: db_instance_number_1, + deregistered_at: deregistered_at + }, + [ + %DatabaseInstanceDeregistered{ + sap_system_id: database_id, + host_id: primary_database_host_id, + instance_number: db_instance_number_1, + deregistered_at: deregistered_at + }, + %DatabaseDeregistered{ + sap_system_id: database_id, + deregistered_at: deregistered_at + } + ], + fn state -> + assert %Database{ + sid: ^db_sid, + instances: [ + %Instance{ + instance_number: ^db_instance_number_2, + sid: ^db_sid, + host_id: ^secondary_database_host_id + } + ], + health: :passing, + deregistered_at: ^deregistered_at + } = state + end + ) + end + + test "should deregister a secondary DB instance" do + database_id = UUID.uuid4() + deregistered_at = DateTime.utc_now() + + instance_number_1 = "00" + instance_number_2 = "01" + + db_sid = fake_sid() + + primary_db_host_id = UUID.uuid4() + secondary_db_host_id = UUID.uuid4() + + assert_events_and_state( + [ + build( + :database_registered_event, + sap_system_id: database_id, + sid: db_sid + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + system_replication: "Primary", + sid: db_sid, + instance_number: instance_number_1, + host_id: primary_db_host_id + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + system_replication: "Secondary", + sid: db_sid, + host_id: secondary_db_host_id, + instance_number: instance_number_2 + ) + ], + %DeregisterDatabaseInstance{ + database_id: database_id, + host_id: secondary_db_host_id, + instance_number: instance_number_2, + deregistered_at: deregistered_at + }, + %DatabaseInstanceDeregistered{ + sap_system_id: database_id, + host_id: secondary_db_host_id, + instance_number: instance_number_2, + deregistered_at: deregistered_at + }, + fn state -> + assert %Database{ + sid: ^db_sid, + deregistered_at: nil, + instances: [%Instance{instance_number: ^instance_number_1}] + } = state + end + ) + end + + test "should deregister the only database instance and deregister the entire database, system replication disabled" do + database_id = UUID.uuid4() + database_host_id = UUID.uuid4() + deregistered_at = DateTime.utc_now() + db_instance_number_1 = "00" + db_sid = fake_sid() + + assert_events_and_state( + [ + build( + :database_registered_event, + sap_system_id: database_id, + sid: db_sid + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + host_id: database_host_id, + instance_number: db_instance_number_1, + system_replication: nil, + sid: db_sid + ) + ], + %DeregisterDatabaseInstance{ + database_id: database_id, + host_id: database_host_id, + instance_number: db_instance_number_1, + deregistered_at: deregistered_at + }, + [ + %DatabaseInstanceDeregistered{ + sap_system_id: database_id, + host_id: database_host_id, + instance_number: db_instance_number_1, + deregistered_at: deregistered_at + }, + %DatabaseDeregistered{ + sap_system_id: database_id, + deregistered_at: deregistered_at + } + ], + fn state -> + assert %Database{ + sid: ^db_sid, + instances: [], + health: :passing, + deregistered_at: ^deregistered_at + } = state + end + ) + end + + test "should deregister a single DB instance of two if no SR enabled" do + database_id = UUID.uuid4() + database_host_id = UUID.uuid4() + second_database_host_id = UUID.uuid4() + deregistered_at = DateTime.utc_now() + db_instance_number_1 = "00" + db_instance_number_2 = "01" + + db_sid = fake_sid() + + assert_events_and_state( + [ + build( + :database_registered_event, + sap_system_id: database_id, + sid: db_sid + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + host_id: database_host_id, + instance_number: db_instance_number_1, + system_replication: nil, + sid: db_sid + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + host_id: second_database_host_id, + instance_number: db_instance_number_2, + system_replication: nil, + sid: db_sid + ) + ], + %DeregisterDatabaseInstance{ + database_id: database_id, + host_id: database_host_id, + instance_number: db_instance_number_1, + deregistered_at: deregistered_at + }, + %DatabaseInstanceDeregistered{ + sap_system_id: database_id, + host_id: database_host_id, + instance_number: db_instance_number_1, + deregistered_at: deregistered_at + }, + fn state -> + assert %Database{ + sid: ^db_sid, + deregistered_at: nil, + instances: [%Instance{instance_number: ^db_instance_number_2}] + } = state + end + ) + end + + test "should deregister the primary instance, the entire database and then the secondary instance" do + database_id = UUID.uuid4() + primary_database_host_id = UUID.uuid4() + secondary_database_host_id = UUID.uuid4() + deregistered_at = DateTime.utc_now() + db_instance_number_1 = "00" + db_instance_number_2 = "01" + + db_sid = fake_sid() + + initial_events = [ + build( + :database_registered_event, + sap_system_id: database_id, + sid: db_sid + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + host_id: primary_database_host_id, + sid: db_sid, + instance_number: db_instance_number_1, + system_replication: "Primary" + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + host_id: secondary_database_host_id, + instance_number: db_instance_number_2, + system_replication: "Secondary" + ) + ] + + assert_events( + initial_events, + [ + %DeregisterDatabaseInstance{ + database_id: database_id, + host_id: primary_database_host_id, + instance_number: db_instance_number_1, + deregistered_at: deregistered_at + }, + %DeregisterDatabaseInstance{ + database_id: database_id, + host_id: secondary_database_host_id, + instance_number: db_instance_number_2, + deregistered_at: deregistered_at + } + ], + [ + %DatabaseInstanceDeregistered{ + sap_system_id: database_id, + host_id: primary_database_host_id, + instance_number: db_instance_number_1, + deregistered_at: deregistered_at + }, + %DatabaseDeregistered{ + sap_system_id: database_id, + deregistered_at: deregistered_at + }, + %DatabaseInstanceDeregistered{ + sap_system_id: database_id, + host_id: secondary_database_host_id, + instance_number: db_instance_number_2, + deregistered_at: deregistered_at + } + ] + ) + end + + test "should correctly deregister the database in a scale out scenario, with two primary and two secondary" do + database_id = UUID.uuid4() + first_primary_database_host_id = UUID.uuid4() + other_primary_database_host_id = UUID.uuid4() + + secondary_database_host_id = UUID.uuid4() + other_secondary_database_host_id = UUID.uuid4() + + deregistered_at = DateTime.utc_now() + + db_instance_number_1 = "00" + db_instance_number_2 = "01" + db_instance_number_3 = "02" + db_instance_number_4 = "03" + + db_sid = fake_sid() + + initial_events = [ + build( + :database_registered_event, + sap_system_id: database_id, + sid: db_sid + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + host_id: first_primary_database_host_id, + sid: db_sid, + instance_number: db_instance_number_1, + system_replication: "Primary" + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + host_id: other_primary_database_host_id, + sid: db_sid, + instance_number: db_instance_number_2, + system_replication: "Primary" + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + host_id: secondary_database_host_id, + instance_number: db_instance_number_3, + system_replication: "Secondary" + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + host_id: other_secondary_database_host_id, + instance_number: db_instance_number_4, + system_replication: "Secondary" + ) + ] + + assert_events( + initial_events, + [ + %DeregisterDatabaseInstance{ + database_id: database_id, + host_id: first_primary_database_host_id, + instance_number: db_instance_number_1, + deregistered_at: deregistered_at + }, + %DeregisterDatabaseInstance{ + database_id: database_id, + host_id: other_primary_database_host_id, + instance_number: db_instance_number_2, + deregistered_at: deregistered_at + }, + %DeregisterDatabaseInstance{ + database_id: database_id, + host_id: secondary_database_host_id, + instance_number: db_instance_number_3, + deregistered_at: deregistered_at + }, + %DeregisterDatabaseInstance{ + database_id: database_id, + host_id: other_secondary_database_host_id, + instance_number: db_instance_number_4, + deregistered_at: deregistered_at + } + ], + [ + %DatabaseInstanceDeregistered{ + sap_system_id: database_id, + host_id: first_primary_database_host_id, + instance_number: db_instance_number_1, + deregistered_at: deregistered_at + }, + %DatabaseInstanceDeregistered{ + sap_system_id: database_id, + host_id: other_primary_database_host_id, + instance_number: db_instance_number_2, + deregistered_at: deregistered_at + }, + %DatabaseDeregistered{ + sap_system_id: database_id, + deregistered_at: deregistered_at + }, + %DatabaseInstanceDeregistered{ + sap_system_id: database_id, + host_id: secondary_database_host_id, + instance_number: db_instance_number_3, + deregistered_at: deregistered_at + }, + %DatabaseInstanceDeregistered{ + sap_system_id: database_id, + host_id: other_secondary_database_host_id, + instance_number: db_instance_number_4, + deregistered_at: deregistered_at + } + ] + ) + end + + test "should deregister the primary instance of database" do + database_id = UUID.uuid4() + deregistered_at = DateTime.utc_now() + + primary_database_host_id = UUID.uuid4() + secondary_database_host_id = UUID.uuid4() + + database_instance_number_1 = "00" + database_instance_number_2 = "00" + + db_sid = fake_sid() + + initial_events = [ + build( + :database_registered_event, + sap_system_id: database_id, + sid: db_sid + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + host_id: primary_database_host_id, + sid: db_sid, + instance_number: database_instance_number_1, + system_replication: "Primary" + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + host_id: secondary_database_host_id, + instance_number: database_instance_number_2, + system_replication: "Secondary" + ) + ] + + assert_events( + initial_events, + [ + %DeregisterDatabaseInstance{ + database_id: database_id, + host_id: primary_database_host_id, + instance_number: database_instance_number_1, + deregistered_at: deregistered_at + } + ], + [ + %DatabaseInstanceDeregistered{ + sap_system_id: database_id, + host_id: primary_database_host_id, + instance_number: database_instance_number_1, + deregistered_at: deregistered_at + }, + %DatabaseDeregistered{ + sap_system_id: database_id, + deregistered_at: deregistered_at + } + ] + ) + end + + test "should not deregister a not registered database instance" do + database_id = UUID.uuid4() + db_sid = fake_sid() + + assert_error( + [ + build( + :database_registered_event, + sap_system_id: database_id, + sid: db_sid + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + sid: db_sid, + host_id: UUID.uuid4(), + instance_number: "00", + system_replication: "Primary" + ) + ], + [ + %DeregisterDatabaseInstance{ + database_id: database_id, + host_id: UUID.uuid4(), + instance_number: "01", + deregistered_at: DateTime.utc_now() + } + ], + {:error, :database_instance_not_registered} + ) + end + + test "should not deregister an already deregistered database instance" do + database_id = UUID.uuid4() + db_sid = fake_sid() + deregistered_host_id = UUID.uuid4() + deregistered_instance_number = "01" + + assert_error( + [ + build( + :database_registered_event, + sap_system_id: database_id, + sid: db_sid + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + sid: db_sid, + host_id: deregistered_host_id, + instance_number: deregistered_instance_number, + system_replication: "Primary" + ), + build( + :database_instance_deregistered_event, + sap_system_id: database_id, + host_id: deregistered_host_id, + instance_number: deregistered_instance_number, + deregistered_at: DateTime.utc_now() + ) + ], + [ + %DeregisterDatabaseInstance{ + database_id: database_id, + host_id: deregistered_host_id, + instance_number: deregistered_instance_number, + deregistered_at: DateTime.utc_now() + } + ], + {:error, :database_instance_not_registered} + ) + end + end + + describe "instance marked absent/present" do + test "should mark as absent a previously registered database instance" do + database_id = Faker.UUID.v4() + sid = fake_sid() + host_id = Faker.UUID.v4() + absent_db_instance_number = "01" + present_db_instance_number = "02" + absent_db_absent_at = DateTime.utc_now() + + initial_events = [ + build( + :database_registered_event, + sap_system_id: database_id, + sid: sid + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + sid: sid, + host_id: host_id, + instance_number: absent_db_instance_number, + system_replication: nil, + system_replication_status: nil + ), + build( + :database_instance_marked_absent_event, + sap_system_id: database_id, + host_id: host_id, + instance_number: absent_db_instance_number, + absent_at: absent_db_absent_at + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + sid: sid, + host_id: host_id, + instance_number: present_db_instance_number, + system_replication: nil, + system_replication_status: nil + ) + ] + + absent_at = DateTime.utc_now() + + assert_events_and_state( + initial_events, + [ + %MarkDatabaseInstanceAbsent{ + instance_number: absent_db_instance_number, + host_id: host_id, + database_id: database_id, + absent_at: absent_at + }, + %MarkDatabaseInstanceAbsent{ + instance_number: present_db_instance_number, + host_id: host_id, + database_id: database_id, + absent_at: absent_at + } + ], + [ + %DatabaseInstanceMarkedAbsent{ + instance_number: present_db_instance_number, + host_id: host_id, + sap_system_id: database_id, + absent_at: absent_at + } + ], + fn state -> + assert %Database{ + sid: ^sid, + instances: [ + %Instance{ + instance_number: ^present_db_instance_number, + absent_at: ^absent_at + }, + %Instance{ + instance_number: ^absent_db_instance_number, + absent_at: ^absent_db_absent_at + } + ] + } = state + end + ) + end + + test "should mark as present an already registered, absent database instance" do + database_id = Faker.UUID.v4() + sid = fake_sid() + host_id = Faker.UUID.v4() + absent_db_instance_number = "01" + present_db_instance_number = "02" + + initial_events = [ + build( + :database_registered_event, + sap_system_id: database_id, + sid: sid + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + sid: sid, + host_id: host_id, + instance_number: absent_db_instance_number, + system_replication: nil, + system_replication_status: nil + ), + build( + :database_instance_marked_absent_event, + sap_system_id: database_id, + host_id: host_id, + instance_number: absent_db_instance_number, + absent_at: DateTime.utc_now() + ), + build( + :database_instance_registered_event, + sap_system_id: database_id, + sid: sid, + host_id: host_id, + instance_number: present_db_instance_number, + system_replication: nil, + system_replication_status: nil + ) + ] + + assert_events_and_state( + initial_events, + [ + %RegisterDatabaseInstance{ + database_id: database_id, + host_id: host_id, + instance_number: absent_db_instance_number, + health: :passing + }, + %RegisterDatabaseInstance{ + database_id: database_id, + host_id: host_id, + instance_number: present_db_instance_number, + health: :passing + } + ], + [ + %DatabaseInstanceMarkedPresent{ + instance_number: absent_db_instance_number, + host_id: host_id, + sap_system_id: database_id + } + ], + fn state -> + assert %Database{ + sid: ^sid, + instances: [ + %Instance{ + absent_at: nil + }, + %Instance{ + absent_at: nil + } + ] + } = state + end + ) + end + end + + defp fake_sid, + do: Enum.join([Faker.Util.letter(), Faker.Util.letter(), Faker.Util.letter()]) +end diff --git a/test/trento/discovery/policies/sap_system_policy_test.exs b/test/trento/discovery/policies/sap_system_policy_test.exs index 987b27a1e9..863f06177a 100644 --- a/test/trento/discovery/policies/sap_system_policy_test.exs +++ b/test/trento/discovery/policies/sap_system_policy_test.exs @@ -10,13 +10,16 @@ defmodule Trento.Discovery.Policies.SapSystemPolicyTest do alias Trento.Discovery.Policies.SapSystemPolicy - alias Trento.SapSystems.Commands.{ - MarkApplicationInstanceAbsent, + alias Trento.Databases.Commands.{ MarkDatabaseInstanceAbsent, - RegisterApplicationInstance, RegisterDatabaseInstance } + alias Trento.SapSystems.Commands.{ + MarkApplicationInstanceAbsent, + RegisterApplicationInstance + } + test "should return the expected commands when a sap_system payload of type database is handled" do assert {:ok, [ @@ -24,7 +27,7 @@ defmodule Trento.Discovery.Policies.SapSystemPolicyTest do features: "HDB|HDB_WORKER", host_id: "779cdd70-e9e2-58ca-b18a-bf3eb3f71244", instance_number: "00", - sap_system_id: "97c4127a-29bc-5315-82bd-8f154bee626f", + database_id: "97c4127a-29bc-5315-82bd-8f154bee626f", sid: "PRD", tenant: "PRD", system_replication: "Primary", @@ -44,7 +47,7 @@ defmodule Trento.Discovery.Policies.SapSystemPolicyTest do features: "HDB|HDB_WORKER", host_id: "9cd46919-5f19-59aa-993e-cf3736c71053", instance_number: "10", - sap_system_id: "6c9208eb-a5bb-57ef-be5c-6422dedab602", + database_id: "6c9208eb-a5bb-57ef-be5c-6422dedab602", sid: "HDP", tenant: "HDP", system_replication: nil, @@ -224,11 +227,11 @@ defmodule Trento.Discovery.Policies.SapSystemPolicyTest do assert {:ok, [ %MarkDatabaseInstanceAbsent{ - sap_system_id: ^database_sap_system_id, + database_id: ^database_sap_system_id, instance_number: ^database_instance_number_1 }, %MarkDatabaseInstanceAbsent{ - sap_system_id: ^database_sap_system_id, + database_id: ^database_sap_system_id, instance_number: ^database_instance_number_2 }, %MarkApplicationInstanceAbsent{ @@ -239,7 +242,7 @@ defmodule Trento.Discovery.Policies.SapSystemPolicyTest do }, %RegisterDatabaseInstance{ instance_number: "00", - sap_system_id: "97c4127a-29bc-5315-82bd-8f154bee626f", + database_id: "97c4127a-29bc-5315-82bd-8f154bee626f", sid: "PRD" } ]} = diff --git a/test/trento/infrastructure/commanded/middleware/enrich_register_application_instance_test.exs b/test/trento/infrastructure/commanded/middleware/enrich_register_application_instance_test.exs index c174881243..ee7851b742 100644 --- a/test/trento/infrastructure/commanded/middleware/enrich_register_application_instance_test.exs +++ b/test/trento/infrastructure/commanded/middleware/enrich_register_application_instance_test.exs @@ -27,7 +27,9 @@ defmodule Trento.Infrastructure.Commanded.Middleware.EnrichRegisterApplicationIn health: :passing ) - assert {:ok, %RegisterApplicationInstance{sap_system_id: ^sap_system_id}} = + expected_sap_system_id = UUID.uuid5(sap_system_id, tenant) + + assert {:ok, %RegisterApplicationInstance{sap_system_id: ^expected_sap_system_id}} = Enrichable.enrich(command, %{}) end diff --git a/test/trento/infrastructure/commanded/process_managers/deregistration_process_manager_test.exs b/test/trento/infrastructure/commanded/process_managers/deregistration_process_manager_test.exs index c3154e8e7d..18f3232b36 100644 --- a/test/trento/infrastructure/commanded/process_managers/deregistration_process_manager_test.exs +++ b/test/trento/infrastructure/commanded/process_managers/deregistration_process_manager_test.exs @@ -32,19 +32,13 @@ defmodule Trento.Infrastructure.Commanded.ProcessManagers.DeregistrationProcessM alias Trento.Clusters.Cluster alias Trento.SapSystems.Instance, as: SapSystemInstance - alias Trento.SapSystems.{ - Application, - Database, - SapSystem - } + alias Trento.SapSystems.SapSystem alias Trento.Clusters.Commands.DeregisterClusterHost alias Trento.Hosts.Commands.DeregisterHost - alias Trento.SapSystems.Commands.{ - DeregisterApplicationInstance, - DeregisterDatabaseInstance - } + alias Trento.Databases.Commands.DeregisterDatabaseInstance + alias Trento.SapSystems.Commands.DeregisterApplicationInstance describe "events interested" do test "should start the process manager when HostRegistered event arrives" do @@ -96,21 +90,13 @@ defmodule Trento.Infrastructure.Commanded.ProcessManagers.DeregistrationProcessM end test "should start process managers when SapSystemRolledUp arrives" do - [%{host_id: db_host_id_1}, %{host_id: db_host_id_2}] = - database_instances = build_list(2, :sap_system_instance) - [%{host_id: app_host_id_1}, %{host_id: app_host_id_2}] = application_instances = build_list(2, :sap_system_instance) - assert {:start, [^db_host_id_1, ^db_host_id_2, ^app_host_id_1, ^app_host_id_2]} = + assert {:start, [^app_host_id_1, ^app_host_id_2]} = DeregistrationProcessManager.interested?(%SapSystemRolledUp{ snapshot: %SapSystem{ - database: %Database{ - instances: database_instances - }, - application: %Application{ - instances: application_instances - } + instances: application_instances } }) end @@ -267,8 +253,7 @@ defmodule Trento.Infrastructure.Commanded.ProcessManagers.DeregistrationProcessM test "should update state when SapSystemRolledUp event received" do sap_system_id = UUID.uuid4() instance_number = "00" - database_instance_number = "01" - application_instance_number = "02" + application_instance_number = "01" initial_state = %DeregistrationProcessManager{ database_instances: [ @@ -281,23 +266,11 @@ defmodule Trento.Infrastructure.Commanded.ProcessManagers.DeregistrationProcessM %SapSystemRolledUp{ sap_system_id: sap_system_id, snapshot: %SapSystem{ - database: %Database{ - instances: [ - %SapSystemInstance{ - instance_number: database_instance_number - }, - %SapSystemInstance{ - instance_number: instance_number - } - ] - }, - application: %Application{ - instances: [ - %SapSystemInstance{ - instance_number: application_instance_number - } - ] - } + instances: [ + %SapSystemInstance{ + instance_number: application_instance_number + } + ] } } ] @@ -308,10 +281,6 @@ defmodule Trento.Infrastructure.Commanded.ProcessManagers.DeregistrationProcessM assert %DeregistrationProcessManager{ database_instances: [ - %Instance{ - sap_system_id: ^sap_system_id, - instance_number: ^database_instance_number - }, %Instance{ sap_system_id: ^sap_system_id, instance_number: ^instance_number @@ -366,7 +335,7 @@ defmodule Trento.Infrastructure.Commanded.ProcessManagers.DeregistrationProcessM assert [ %DeregisterDatabaseInstance{ - sap_system_id: ^sap_system_id, + database_id: ^sap_system_id, instance_number: ^db_instance_number, host_id: ^host_id, deregistered_at: ^requested_at @@ -434,7 +403,7 @@ defmodule Trento.Infrastructure.Commanded.ProcessManagers.DeregistrationProcessM assert [ %DeregisterDatabaseInstance{ - sap_system_id: ^sap_system_id, + database_id: ^sap_system_id, instance_number: ^db_instance_number, host_id: ^host_id, deregistered_at: ^requested_at diff --git a/test/trento/sap_systems/sap_system_test.exs b/test/trento/sap_systems/sap_system_test.exs index cb18270ac3..390a6a19c3 100644 --- a/test/trento/sap_systems/sap_system_test.exs +++ b/test/trento/sap_systems/sap_system_test.exs @@ -7,11 +7,8 @@ defmodule Trento.SapSystems.SapSystemTest do alias Trento.SapSystems.Commands.{ DeregisterApplicationInstance, - DeregisterDatabaseInstance, MarkApplicationInstanceAbsent, - MarkDatabaseInstanceAbsent, RegisterApplicationInstance, - RegisterDatabaseInstance, RollUpSapSystem } @@ -22,16 +19,6 @@ defmodule Trento.SapSystems.SapSystemTest do ApplicationInstanceMarkedPresent, ApplicationInstanceMoved, ApplicationInstanceRegistered, - DatabaseDeregistered, - DatabaseHealthChanged, - DatabaseInstanceDeregistered, - DatabaseInstanceHealthChanged, - DatabaseInstanceMarkedAbsent, - DatabaseInstanceMarkedPresent, - DatabaseInstanceRegistered, - DatabaseInstanceSystemReplicationChanged, - DatabaseRegistered, - DatabaseRestored, SapSystemDeregistered, SapSystemHealthChanged, SapSystemRegistered, @@ -43,311 +30,11 @@ defmodule Trento.SapSystems.SapSystemTest do } alias Trento.SapSystems.{ - Application, - Database, Instance, SapSystem } describe "SAP System registration" do - test "should fail when a sap system does not exists and the database instance has Secondary role" do - command = - build(:register_database_instance_command, - system_replication: "Secondary" - ) - - assert_error( - command, - {:error, :sap_system_not_registered} - ) - end - - test "should create an incomplete SAP system aggregate and register a database instance when the system replication is disabled" do - sap_system_id = Faker.UUID.v4() - sid = Faker.StarWars.planet() - tenant = Faker.Beer.style() - instance_number = "00" - instance_hostname = Faker.Airports.iata() - features = Faker.Pokemon.name() - http_port = 80 - https_port = 443 - start_priority = "0.9" - host_id = Faker.UUID.v4() - - assert_events_and_state( - [], - RegisterDatabaseInstance.new!(%{ - sap_system_id: sap_system_id, - sid: sid, - tenant: tenant, - instance_number: instance_number, - instance_hostname: instance_hostname, - features: features, - http_port: http_port, - https_port: https_port, - start_priority: start_priority, - host_id: host_id, - system_replication: nil, - health: :passing - }), - [ - %DatabaseRegistered{ - sap_system_id: sap_system_id, - sid: sid, - health: :passing - }, - %DatabaseInstanceRegistered{ - sap_system_id: sap_system_id, - sid: sid, - tenant: tenant, - instance_number: instance_number, - instance_hostname: instance_hostname, - features: features, - http_port: http_port, - https_port: https_port, - start_priority: start_priority, - host_id: host_id, - system_replication: nil, - system_replication_status: nil, - health: :passing - } - ], - %SapSystem{ - sap_system_id: sap_system_id, - # The SAP System aggregate is not complete yet. - # The sid will be set when the first application instance is registered. - sid: nil, - database: %Database{ - sid: sid, - health: :passing, - instances: [ - %Instance{ - sid: sid, - system_replication: nil, - system_replication_status: nil, - instance_number: instance_number, - features: features, - host_id: host_id, - health: :passing, - absent_at: nil - } - ] - } - } - ) - end - - test "should create an incomplete SAP system aggregate and register a database instance when the system replication is enabled and the database role is primary" do - sap_system_id = Faker.UUID.v4() - sid = Faker.StarWars.planet() - tenant = Faker.Beer.style() - instance_number = "00" - instance_hostname = Faker.Airports.iata() - features = Faker.Pokemon.name() - http_port = 80 - https_port = 443 - start_priority = "0.9" - host_id = Faker.UUID.v4() - - assert_events_and_state( - [], - RegisterDatabaseInstance.new!(%{ - sap_system_id: sap_system_id, - sid: sid, - tenant: tenant, - instance_number: instance_number, - instance_hostname: instance_hostname, - features: features, - http_port: http_port, - https_port: https_port, - start_priority: start_priority, - host_id: host_id, - system_replication: "Primary", - system_replication_status: "ACTIVE", - health: :passing - }), - [ - %DatabaseRegistered{ - sap_system_id: sap_system_id, - sid: sid, - health: :passing - }, - %DatabaseInstanceRegistered{ - sap_system_id: sap_system_id, - sid: sid, - tenant: tenant, - instance_number: instance_number, - instance_hostname: instance_hostname, - features: features, - http_port: http_port, - https_port: https_port, - start_priority: start_priority, - host_id: host_id, - system_replication: "Primary", - system_replication_status: "ACTIVE", - health: :passing - } - ], - %SapSystem{ - sap_system_id: sap_system_id, - # The SAP System aggregate is not complete yet. - # The sid will be set when the first application instance is registered. - sid: nil, - database: %Database{ - sid: sid, - health: :passing, - instances: [ - %Instance{ - sid: sid, - system_replication: "Primary", - system_replication_status: "ACTIVE", - instance_number: instance_number, - features: features, - host_id: host_id, - health: :passing - } - ] - } - } - ) - end - - test "should add a database instance to an existing Database" do - sap_system_id = Faker.UUID.v4() - sid = Faker.StarWars.planet() - tenant = Faker.Beer.style() - instance_number = "00" - features = Faker.Pokemon.name() - host_id = Faker.UUID.v4() - - initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - sid: sid, - tenant: tenant, - instance_number: "10" - ) - ] - - assert_events_and_state( - initial_events, - build( - :register_database_instance_command, - sap_system_id: sap_system_id, - sid: sid, - tenant: tenant, - instance_number: instance_number, - features: features, - host_id: host_id, - health: :passing - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - sid: sid, - tenant: tenant, - instance_number: instance_number, - features: features, - host_id: host_id, - health: :passing - ), - fn state -> - assert %SapSystem{ - database: %Database{ - instances: [ - %Instance{ - sid: ^sid, - instance_number: ^instance_number, - features: ^features, - host_id: ^host_id, - health: :passing - } - | _ - ] - } - } = state - end - ) - end - - test "should not add a database instance if the database instance was already registered" do - database_registered_event = build(:database_registered_event) - - database_instance_registered_event = - build( - :database_instance_registered_event, - sap_system_id: database_registered_event.sap_system_id - ) - - initial_events = [ - database_registered_event, - database_instance_registered_event - ] - - assert_events( - initial_events, - build( - :register_database_instance_command, - sap_system_id: database_registered_event.sap_system_id, - sid: database_instance_registered_event.sid, - tenant: database_instance_registered_event.tenant, - instance_number: database_instance_registered_event.instance_number, - features: database_instance_registered_event.features, - host_id: database_instance_registered_event.host_id, - system_replication: database_instance_registered_event.system_replication, - system_replication_status: database_instance_registered_event.system_replication_status, - health: :passing - ), - [] - ) - end - - test "should change the system replication of a database instance" do - database_registered_event = build(:database_registered_event) - - database_instance_registered_event = - build( - :database_instance_registered_event, - sap_system_id: database_registered_event.sap_system_id, - system_replication: "Secondary", - system_replication_status: "" - ) - - initial_events = [ - database_registered_event, - database_instance_registered_event - ] - - assert_events( - initial_events, - build( - :register_database_instance_command, - sap_system_id: database_registered_event.sap_system_id, - sid: database_instance_registered_event.sid, - tenant: database_instance_registered_event.tenant, - instance_number: database_instance_registered_event.instance_number, - features: database_instance_registered_event.features, - host_id: database_instance_registered_event.host_id, - system_replication: "Primary", - system_replication_status: "ACTIVE", - health: :passing - ), - %DatabaseInstanceSystemReplicationChanged{ - sap_system_id: database_registered_event.sap_system_id, - host_id: database_instance_registered_event.host_id, - instance_number: database_instance_registered_event.instance_number, - system_replication: "Primary", - system_replication_status: "ACTIVE" - } - ) - end - test "should register a SAP System and add an application instance when a MESSAGESERVER instance is already present and a new ABAP instance is added" do sap_system_id = Faker.UUID.v4() sid = Faker.StarWars.planet() @@ -361,17 +48,6 @@ defmodule Trento.SapSystems.SapSystemTest do ensa_version = EnsaVersion.ensa1() initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - sid: sid, - tenant: tenant - ), build(:application_instance_registered_event, sap_system_id: sap_system_id, sid: sid, @@ -423,22 +99,19 @@ defmodule Trento.SapSystems.SapSystemTest do assert %SapSystem{ sid: ^sid, ensa_version: ^ensa_version, - application: %Application{ - sid: ^sid, - instances: [ - %Instance{ - sid: ^sid, - instance_number: "10", - features: "ABAP", - host_id: ^host_id, - health: :passing, - absent_at: nil - }, - %Instance{ - features: "MESSAGESERVER" - } - ] - } + instances: [ + %Instance{ + sid: ^sid, + instance_number: "10", + features: "ABAP", + host_id: ^host_id, + health: :passing, + absent_at: nil + }, + %Instance{ + features: "MESSAGESERVER" + } + ] } = state end ) @@ -460,16 +133,6 @@ defmodule Trento.SapSystems.SapSystemTest do cluster_id = Faker.UUID.v4() initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - sid: sid - ), build(:application_instance_registered_event, sap_system_id: sap_system_id, sid: sid, @@ -523,16 +186,14 @@ defmodule Trento.SapSystems.SapSystemTest do ], fn state -> assert %SapSystem{ - application: %Application{ - instances: [ - %Instance{ - sid: ^sid, - instance_number: ^instance_number, - host_id: ^new_host_id - } - | _ - ] - } + instances: [ + %Instance{ + sid: ^sid, + instance_number: ^instance_number, + host_id: ^new_host_id + } + | _ + ] } = state end ) @@ -554,16 +215,6 @@ defmodule Trento.SapSystems.SapSystemTest do cluster_id = Faker.UUID.v4() initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - sid: sid - ), build(:application_instance_registered_event, sap_system_id: sap_system_id, sid: sid, @@ -628,16 +279,6 @@ defmodule Trento.SapSystems.SapSystemTest do ensa_version = EnsaVersion.ensa1() initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - sid: sid - ), build(:application_instance_registered_event, sap_system_id: sap_system_id, sid: sid, @@ -697,17 +338,15 @@ defmodule Trento.SapSystems.SapSystemTest do ], fn state -> assert %SapSystem{ - application: %Application{ - instances: [ - %Instance{ - sid: ^sid, - instance_number: ^instance_number, - host_id: ^new_host_id - }, - _, - _ - ] - } + instances: [ + %Instance{ + sid: ^sid, + instance_number: ^instance_number, + host_id: ^new_host_id + }, + _, + _ + ] } = state end ) @@ -727,16 +366,6 @@ defmodule Trento.SapSystems.SapSystemTest do ensa_version = EnsaVersion.ensa1() initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - sid: sid - ), build(:application_instance_registered_event, sap_system_id: sap_system_id, sid: sid, @@ -782,16 +411,14 @@ defmodule Trento.SapSystems.SapSystemTest do [], fn state -> assert %SapSystem{ - application: %Application{ - instances: [ - %Instance{ - sid: ^sid, - instance_number: ^instance_number, - host_id: ^old_host_id - }, - _ - ] - } + instances: [ + %Instance{ + sid: ^sid, + instance_number: ^instance_number, + host_id: ^old_host_id + }, + _ + ] } = state end ) @@ -805,16 +432,6 @@ defmodule Trento.SapSystems.SapSystemTest do host_id = Faker.UUID.v4() initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - sid: sid - ), build(:application_instance_registered_event, sap_system_id: sap_system_id, sid: sid, @@ -854,10 +471,7 @@ defmodule Trento.SapSystems.SapSystemTest do fn state -> assert %SapSystem{ sid: ^sid, - ensa_version: ^ensa_version, - application: %Application{ - sid: ^sid - } + ensa_version: ^ensa_version } = state end ) @@ -871,16 +485,6 @@ defmodule Trento.SapSystems.SapSystemTest do host_id = Faker.UUID.v4() initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - sid: sid - ), build(:application_instance_registered_event, sap_system_id: sap_system_id, sid: sid, @@ -915,10 +519,7 @@ defmodule Trento.SapSystems.SapSystemTest do fn state -> assert %SapSystem{ sid: ^sid, - ensa_version: ^ensa_version, - application: %Application{ - sid: ^sid - } + ensa_version: ^ensa_version } = state end ) @@ -932,17 +533,7 @@ defmodule Trento.SapSystems.SapSystemTest do host_id = Faker.UUID.v4() initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - sid: sid - ), - build(:application_instance_registered_event, + build(:application_instance_registered_event, sap_system_id: sap_system_id, sid: sid, features: "MESSAGESERVER", @@ -976,10 +567,7 @@ defmodule Trento.SapSystems.SapSystemTest do fn state -> assert %SapSystem{ sid: ^sid, - ensa_version: ^ensa_version, - application: %Application{ - sid: ^sid - } + ensa_version: ^ensa_version } = state end ) @@ -998,17 +586,6 @@ defmodule Trento.SapSystems.SapSystemTest do ensa_version = EnsaVersion.ensa1() initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - sid: sid, - tenant: tenant - ), build(:application_instance_registered_event, sap_system_id: sap_system_id, sid: sid, @@ -1059,21 +636,18 @@ defmodule Trento.SapSystems.SapSystemTest do fn state -> assert %SapSystem{ sid: ^sid, - application: %Application{ - sid: ^sid, - instances: [ - %Instance{ - sid: ^sid, - instance_number: "00", - features: "MESSAGESERVER", - host_id: ^host_id, - health: :passing - }, - %Instance{ - features: "ABAP" - } - ] - } + instances: [ + %Instance{ + sid: ^sid, + instance_number: "00", + features: "MESSAGESERVER", + host_id: ^host_id, + health: :passing + }, + %Instance{ + features: "ABAP" + } + ] } = state end ) @@ -1091,19 +665,7 @@ defmodule Trento.SapSystems.SapSystemTest do host_id = Faker.UUID.v4() ensa_version = EnsaVersion.ensa1() - initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - sid: sid, - tenant: tenant - ) - ] + initial_events = [] assert_events_and_state( initial_events, @@ -1139,18 +701,15 @@ defmodule Trento.SapSystems.SapSystemTest do fn state -> assert %SapSystem{ sid: nil, - application: %Application{ - sid: ^sid, - instances: [ - %Instance{ - sid: ^sid, - instance_number: "00", - features: "ABAP", - host_id: ^host_id, - health: :passing - } - ] - } + instances: [ + %Instance{ + sid: ^sid, + instance_number: "00", + features: "ABAP", + host_id: ^host_id, + health: :passing + } + ] } = state end ) @@ -1168,19 +727,7 @@ defmodule Trento.SapSystems.SapSystemTest do host_id = Faker.UUID.v4() ensa_version = EnsaVersion.ensa1() - initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - sid: sid, - tenant: tenant - ) - ] + initial_events = [] assert_events_and_state( initial_events, @@ -1216,18 +763,15 @@ defmodule Trento.SapSystems.SapSystemTest do fn state -> assert %SapSystem{ sid: nil, - application: %Application{ - sid: ^sid, - instances: [ - %Instance{ - sid: ^sid, - instance_number: "00", - features: "MESSAGESERVER", - host_id: ^host_id, - health: :passing - } - ] - } + instances: [ + %Instance{ + sid: ^sid, + instance_number: "00", + features: "MESSAGESERVER", + host_id: ^host_id, + health: :passing + } + ] } = state end ) @@ -1238,8 +782,6 @@ defmodule Trento.SapSystems.SapSystemTest do sid = Faker.StarWars.planet() initial_events = [ - build(:database_registered_event, sap_system_id: sap_system_id, sid: sid), - build(:database_instance_registered_event, sap_system_id: sap_system_id, sid: sid), build(:application_instance_registered_event, sap_system_id: sap_system_id, sid: sid), build(:sap_system_registered_event, sap_system_id: sap_system_id, sid: sid) ] @@ -1274,19 +816,17 @@ defmodule Trento.SapSystems.SapSystemTest do ), fn state -> assert %SapSystem{ - application: %Application{ - sid: ^sid, - instances: [ - %Instance{ - sid: ^sid, - instance_number: ^new_instance_number, - features: ^new_instance_features, - host_id: ^new_instance_host_id, - health: :passing - } - | _ - ] - } + sid: ^sid, + instances: [ + %Instance{ + sid: ^sid, + instance_number: ^new_instance_number, + features: ^new_instance_features, + host_id: ^new_instance_host_id, + health: :passing + } + | _ + ] } = state end ) @@ -1299,10 +839,7 @@ defmodule Trento.SapSystems.SapSystemTest do build(:application_instance_registered_event, sap_system_id: sap_system_id) initial_events = [ - build(:database_registered_event, sap_system_id: sap_system_id), - build(:database_instance_registered_event, sap_system_id: sap_system_id), - application_instance_registered_event, - build(:sap_system_registered_event, sap_system_id: sap_system_id) + application_instance_registered_event ] assert_events( @@ -1324,197 +861,6 @@ defmodule Trento.SapSystems.SapSystemTest do end describe "SAP System health" do - test "should change the health of a Database when a new Database instance is registered" do - sap_system_id = Faker.UUID.v4() - sid = Faker.StarWars.planet() - tenant = Faker.Beer.style() - instance_number = "00" - features = Faker.Pokemon.name() - host_id = Faker.UUID.v4() - - initial_events = [ - build(:database_registered_event, sap_system_id: sap_system_id), - build(:database_instance_registered_event, sap_system_id: sap_system_id) - ] - - assert_events_and_state( - initial_events, - build( - :register_database_instance_command, - sap_system_id: sap_system_id, - sid: sid, - tenant: tenant, - instance_number: instance_number, - features: features, - host_id: host_id, - health: :critical - ), - [ - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - sid: sid, - tenant: tenant, - instance_number: instance_number, - features: features, - host_id: host_id, - health: :critical - ), - %DatabaseHealthChanged{ - sap_system_id: sap_system_id, - health: :critical - } - ], - fn state -> - %SapSystem{ - database: %Database{ - health: :critical, - instances: [ - %Instance{ - health: :critical - }, - %Instance{ - health: :passing - } - ] - } - } = state - end - ) - end - - test "should change the health of a Database when a Database instance has changed the health status" do - sap_system_id = Faker.UUID.v4() - host_id = Faker.UUID.v4() - instance_number = "00" - - database_instance_registered_event = - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: host_id, - instance_number: instance_number - ) - - initial_events = [ - build(:database_registered_event, sap_system_id: sap_system_id), - database_instance_registered_event - ] - - assert_events_and_state( - initial_events, - build( - :register_database_instance_command, - sap_system_id: sap_system_id, - sid: database_instance_registered_event.sid, - tenant: database_instance_registered_event.tenant, - instance_number: instance_number, - features: database_instance_registered_event.features, - host_id: host_id, - health: :critical - ), - [ - %DatabaseInstanceHealthChanged{ - sap_system_id: sap_system_id, - instance_number: instance_number, - host_id: host_id, - health: :critical - }, - %DatabaseHealthChanged{ - sap_system_id: sap_system_id, - health: :critical - } - ], - fn state -> - assert %SapSystem{ - database: %Database{ - health: :critical, - instances: [ - %Instance{ - instance_number: ^instance_number, - host_id: ^host_id, - health: :critical - } - ] - } - } = state - end - ) - end - - test "should not change the health of a Database if no instance has changed the health status" do - sap_system_id = Faker.UUID.v4() - - new_instance_number = "20" - new_instance_features = Faker.Pokemon.name() - new_instance_host_id = Faker.UUID.v4() - - database_instance_registered_event = - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - health: :warning - ) - - initial_events = [ - build(:database_registered_event, sap_system_id: sap_system_id, health: :warning), - database_instance_registered_event - ] - - assert_events_and_state( - initial_events, - [ - build( - :register_database_instance_command, - sap_system_id: sap_system_id, - sid: database_instance_registered_event.sid, - tenant: database_instance_registered_event.tenant, - instance_number: database_instance_registered_event.instance_number, - features: database_instance_registered_event.features, - host_id: database_instance_registered_event.host_id, - health: :warning - ), - build( - :register_database_instance_command, - sap_system_id: sap_system_id, - sid: database_instance_registered_event.sid, - tenant: database_instance_registered_event.tenant, - instance_number: new_instance_number, - features: new_instance_features, - host_id: new_instance_host_id, - health: :warning - ) - ], - [ - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - sid: database_instance_registered_event.sid, - tenant: database_instance_registered_event.tenant, - instance_number: new_instance_number, - features: new_instance_features, - host_id: new_instance_host_id, - health: :warning - ) - ], - fn state -> - assert %SapSystem{ - database: %Database{ - health: :warning, - instances: [ - %Instance{ - health: :warning - }, - %Instance{ - health: :warning - } - ] - } - } = state - end - ) - end - test "should change the health of a SAP System when a new Application instance is registered" do sap_system_id = Faker.UUID.v4() sid = Faker.StarWars.planet() @@ -1526,17 +872,6 @@ defmodule Trento.SapSystems.SapSystemTest do ensa_version = EnsaVersion.ensa1() initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - sid: sid, - tenant: tenant - ), build(:application_instance_registered_event, sap_system_id: sap_system_id, sid: sid, @@ -1581,16 +916,14 @@ defmodule Trento.SapSystems.SapSystemTest do assert %SapSystem{ health: :critical, ensa_version: ^ensa_version, - application: %Application{ - instances: [ - %Instance{ - health: :critical - }, - %Instance{ - health: :passing - } - ] - } + instances: [ + %Instance{ + health: :critical + }, + %Instance{ + health: :passing + } + ] } = state end ) @@ -1606,8 +939,6 @@ defmodule Trento.SapSystems.SapSystemTest do build(:sap_system_registered_event, sap_system_id: sap_system_id) initial_events = [ - build(:database_registered_event, sap_system_id: sap_system_id), - build(:database_instance_registered_event, sap_system_id: sap_system_id), application_instance_registered, sap_system_registered_event ] @@ -1640,13 +971,11 @@ defmodule Trento.SapSystems.SapSystemTest do fn state -> assert %SapSystem{ health: :critical, - application: %Application{ - instances: [ - %Instance{ - health: :critical - } - ] - } + instances: [ + %Instance{ + health: :critical + } + ] } = state end ) @@ -1670,12 +999,6 @@ defmodule Trento.SapSystems.SapSystemTest do build(:sap_system_registered_event, sap_system_id: sap_system_id, health: :warning) initial_events = [ - build(:database_registered_event, sap_system_id: sap_system_id), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - health: :warning - ), application_instance_registered_event, sap_system_registered_event ] @@ -1720,76 +1043,18 @@ defmodule Trento.SapSystems.SapSystemTest do fn state -> assert %SapSystem{ health: :warning, - application: %Application{ - instances: [ - %Instance{ - health: :warning - }, - %Instance{ - health: :warning - } - ] - } + instances: [ + %Instance{ + health: :warning + }, + %Instance{ + health: :warning + } + ] } = state end ) end - - test "should change the health of a SAP System when the Database has changed the health status" do - sap_system_id = Faker.UUID.v4() - - new_instance_number = "20" - new_instance_features = Faker.Pokemon.name() - new_instance_host_id = Faker.UUID.v4() - - initial_events = [ - build(:database_registered_event, sap_system_id: sap_system_id), - database_instance_registered_event = - build(:database_instance_registered_event, sap_system_id: sap_system_id), - build(:application_instance_registered_event, sap_system_id: sap_system_id), - build(:sap_system_registered_event, sap_system_id: sap_system_id) - ] - - assert_events_and_state( - initial_events, - build( - :register_database_instance_command, - sap_system_id: sap_system_id, - sid: database_instance_registered_event.sid, - tenant: database_instance_registered_event.tenant, - instance_number: new_instance_number, - features: new_instance_features, - host_id: new_instance_host_id, - health: :warning - ), - [ - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - sid: database_instance_registered_event.sid, - tenant: database_instance_registered_event.tenant, - instance_number: new_instance_number, - features: new_instance_features, - host_id: new_instance_host_id, - health: :warning - ), - %DatabaseHealthChanged{ - sap_system_id: sap_system_id, - health: :warning - }, - %SapSystemHealthChanged{ - sap_system_id: sap_system_id, - health: :warning - } - ], - fn state -> - assert %SapSystem{health: :warning} = state - end - ) - end - - test "should update the SAP system if some of the fields have been changed" do - end end describe "rollup" do @@ -1804,15 +1069,10 @@ defmodule Trento.SapSystems.SapSystemTest do sap_system_id = UUID.uuid4() sid = UUID.uuid4() - database_instance_registered_event = - build(:database_instance_registered_event, sap_system_id: sap_system_id, sid: sid) - application_instance_registered_event = build(:application_instance_registered_event, sap_system_id: sap_system_id, sid: sid) initial_events = [ - build(:database_registered_event, sap_system_id: sap_system_id, sid: sid), - database_instance_registered_event, application_instance_registered_event, %{ensa_version: ensa_version} = build(:sap_system_registered_event, sap_system_id: sap_system_id, sid: sid) @@ -1828,36 +1088,17 @@ defmodule Trento.SapSystems.SapSystemTest do sid: sid, health: :passing, ensa_version: ensa_version, - application: %Application{ - sid: sid, - instances: [ - %Instance{ - sid: sid, - instance_number: application_instance_registered_event.instance_number, - health: application_instance_registered_event.health, - features: application_instance_registered_event.features, - host_id: application_instance_registered_event.host_id, - system_replication: nil, - system_replication_status: nil - } - ] - }, - database: %Database{ - sid: sid, - health: :passing, - instances: [ - %Instance{ - sid: sid, - instance_number: database_instance_registered_event.instance_number, - health: database_instance_registered_event.health, - features: database_instance_registered_event.features, - host_id: database_instance_registered_event.host_id, - system_replication: database_instance_registered_event.system_replication, - system_replication_status: - database_instance_registered_event.system_replication_status - } - ] - }, + instances: [ + %Instance{ + sid: sid, + instance_number: application_instance_registered_event.instance_number, + health: application_instance_registered_event.health, + features: application_instance_registered_event.features, + host_id: application_instance_registered_event.host_id, + system_replication: nil, + system_replication_status: nil + } + ], rolling_up: false } }, @@ -1872,8 +1113,6 @@ defmodule Trento.SapSystems.SapSystemTest do sid = UUID.uuid4() initial_events = [ - build(:database_registered_event, sap_system_id: sap_system_id, sid: sid), - build(:database_instance_registered_event, sap_system_id: sap_system_id, sid: sid), build(:application_instance_registered_event, sap_system_id: sap_system_id, sid: sid), build(:sap_system_registered_event, sap_system_id: sap_system_id, sid: sid), %SapSystemRollUpRequested{ @@ -1884,17 +1123,10 @@ defmodule Trento.SapSystems.SapSystemTest do assert_error( initial_events, - RegisterDatabaseInstance.new!(%{ - sap_system_id: sap_system_id, - sid: Faker.StarWars.planet(), - tenant: Faker.UUID.v4(), - host_id: Faker.UUID.v4(), - instance_number: "00", - features: Faker.Pokemon.name(), - http_port: 8080, - https_port: 8443, - health: :passing - }), + build( + :register_application_instance_command, + sap_system_id: sap_system_id + ), {:error, :sap_system_rolling_up} ) @@ -1941,45 +1173,18 @@ defmodule Trento.SapSystems.SapSystemTest do end describe "tombstoning" do - test "should tombstone a deregistered SAP system when no application and no database instances are left" do + test "should tombstone a deregistered SAP system when no application instances are left" do sap_system_id = UUID.uuid4() - host_id = UUID.uuid4() - secondary_database_host_id = UUID.uuid4() deregistered_at = DateTime.utc_now() - db_instance_number_1 = "00" - db_instance_number_2 = "01" - message_server_host_id = UUID.uuid4() message_server_instance_number = "00" abap_host_id = UUID.uuid4() abap_instance_number = "01" - db_sid = fake_sid() application_sid = fake_sid() initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: db_sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: host_id, - instance_number: db_instance_number_1, - system_replication: "Primary", - sid: db_sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: secondary_database_host_id, - instance_number: db_instance_number_2, - system_replication: "Secondary", - sid: db_sid - ), build( :application_instance_registered_event, sap_system_id: sap_system_id, @@ -2006,18 +1211,6 @@ defmodule Trento.SapSystems.SapSystemTest do assert_events_and_state( initial_events, [ - %DeregisterDatabaseInstance{ - sap_system_id: sap_system_id, - host_id: host_id, - instance_number: db_instance_number_1, - deregistered_at: deregistered_at - }, - %DeregisterDatabaseInstance{ - sap_system_id: sap_system_id, - host_id: secondary_database_host_id, - instance_number: db_instance_number_2, - deregistered_at: deregistered_at - }, %DeregisterApplicationInstance{ sap_system_id: sap_system_id, host_id: message_server_host_id, @@ -2032,32 +1225,16 @@ defmodule Trento.SapSystems.SapSystemTest do } ], [ - %DatabaseInstanceDeregistered{ - sap_system_id: sap_system_id, - host_id: host_id, - instance_number: db_instance_number_1, - deregistered_at: deregistered_at - }, - %DatabaseDeregistered{ + %ApplicationInstanceDeregistered{ sap_system_id: sap_system_id, + host_id: message_server_host_id, + instance_number: message_server_instance_number, deregistered_at: deregistered_at }, %SapSystemDeregistered{ sap_system_id: sap_system_id, deregistered_at: deregistered_at }, - %DatabaseInstanceDeregistered{ - sap_system_id: sap_system_id, - host_id: secondary_database_host_id, - instance_number: db_instance_number_2, - deregistered_at: deregistered_at - }, - %ApplicationInstanceDeregistered{ - sap_system_id: sap_system_id, - host_id: message_server_host_id, - instance_number: message_server_instance_number, - deregistered_at: deregistered_at - }, %ApplicationInstanceDeregistered{ sap_system_id: sap_system_id, host_id: abap_host_id, @@ -2070,14 +1247,7 @@ defmodule Trento.SapSystems.SapSystemTest do ], fn sap_system -> assert %SapSystem{ - database: %Database{ - deregistered_at: ^deregistered_at, - sid: ^db_sid, - instances: [] - }, - application: %Application{ - instances: [] - }, + instances: [], deregistered_at: ^deregistered_at, sid: ^application_sid } = sap_system @@ -2087,18 +1257,13 @@ defmodule Trento.SapSystems.SapSystemTest do end describe "deregistration" do - test "should not restore a deregistered database when the registering database instance has Secondary role" do + test "should not restore a sap system when no abap/messageserver instances are present" do sap_system_id = UUID.uuid4() - primary_database_host_id = UUID.uuid4() - secondary_database_host_id = UUID.uuid4() + database_host_id = UUID.uuid4() deregistered_at = DateTime.utc_now() - db_instance_number_1 = "00" - db_instance_number_2 = "01" - - db_sid = fake_sid() application_sid = fake_sid() message_server_host_id = UUID.uuid4() @@ -2107,27 +1272,6 @@ defmodule Trento.SapSystems.SapSystemTest do abap_instance_number = "01" initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: db_sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: primary_database_host_id, - sid: db_sid, - instance_number: db_instance_number_1, - system_replication: "Primary" - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: secondary_database_host_id, - instance_number: db_instance_number_2, - system_replication: "Secondary", - sid: db_sid - ), build( :application_instance_registered_event, sap_system_id: sap_system_id, @@ -2149,179 +1293,59 @@ defmodule Trento.SapSystems.SapSystemTest do sap_system_id: sap_system_id, sid: application_sid ), - build(:database_instance_deregistered_event, - sap_system_id: sap_system_id, - host_id: primary_database_host_id, - instance_number: db_instance_number_1, - deregistered_at: deregistered_at - ), - build(:database_deregistered_event, + build(:sap_system_deregistered_event, sap_system_id: sap_system_id, deregistered_at: deregistered_at ), - build(:sap_system_deregistered_event, + build(:application_instance_deregistered_event, sap_system_id: sap_system_id, - deregistered_at: deregistered_at + deregistered_at: deregistered_at, + instance_number: message_server_instance_number, + host_id: message_server_host_id ) ] command = - build(:register_database_instance_command, - system_replication: "Secondary", - sid: db_sid, - sap_system_id: sap_system_id - ) - - assert_error( - initial_events, - command, - {:error, :sap_system_not_registered} - ) - end - - test "should restore a deregistered database when the registering database instance has system replication disabled, with database instance leftovers" do - sap_system_id = UUID.uuid4() - - primary_database_host_id = UUID.uuid4() - secondary_database_host_id = UUID.uuid4() - - deregistered_at = DateTime.utc_now() - - db_instance_number_1 = "00" - db_instance_number_2 = "01" - - db_sid = fake_sid() - application_sid = fake_sid() - - message_server_host_id = UUID.uuid4() - message_server_instance_number = "00" - abap_host_id = UUID.uuid4() - abap_instance_number = "01" - - initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: db_sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: primary_database_host_id, - sid: db_sid, - instance_number: db_instance_number_1, - system_replication: "Primary" - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: secondary_database_host_id, - instance_number: db_instance_number_2, - system_replication: "Secondary", - sid: db_sid - ), build( - :application_instance_registered_event, - sap_system_id: sap_system_id, - features: "MESSAGESERVER|ENQUE", - host_id: message_server_host_id, - instance_number: message_server_instance_number, - sid: application_sid - ), - build( - :application_instance_registered_event, - sap_system_id: sap_system_id, - features: "ABAP|GATEWAY|ICMAN|IGS", - host_id: abap_host_id, - instance_number: abap_instance_number, - sid: application_sid - ), - build( - :sap_system_registered_event, - sap_system_id: sap_system_id, - sid: application_sid - ), - build(:database_instance_deregistered_event, - sap_system_id: sap_system_id, - host_id: primary_database_host_id, - instance_number: db_instance_number_1, - deregistered_at: deregistered_at - ), - build(:database_deregistered_event, - sap_system_id: sap_system_id, - deregistered_at: deregistered_at - ), - build(:sap_system_deregistered_event, + :register_application_instance_command, sap_system_id: sap_system_id, - deregistered_at: deregistered_at - ) - ] - - %{features: features, instance_number: instance_number, health: health} = - command = - build(:register_database_instance_command, - system_replication: nil, - sid: db_sid, - sap_system_id: sap_system_id + sid: application_sid, + db_host: database_host_id, + features: "IGS" ) assert_events_and_state( initial_events, command, [ - %DatabaseInstanceRegistered{ + %ApplicationInstanceRegistered{ sap_system_id: sap_system_id, - sid: db_sid, - tenant: command.tenant, + sid: application_sid, + host_id: command.host_id, instance_number: command.instance_number, instance_hostname: command.instance_hostname, features: command.features, http_port: command.http_port, https_port: command.https_port, start_priority: command.start_priority, - host_id: command.host_id, - system_replication: command.system_replication, - system_replication_status: command.system_replication_status, - health: command.health - }, - %DatabaseRestored{ - sap_system_id: sap_system_id, health: command.health } ], fn sap_system -> assert %SapSystem{ - deregistered_at: ^deregistered_at, - database: %Database{ - deregistered_at: nil, - sid: ^db_sid, - instances: [ - %Instance{ - sid: ^db_sid, - instance_number: ^instance_number, - features: ^features, - health: ^health - }, - %Instance{} - ] - } + deregistered_at: ^deregistered_at } = sap_system end ) end - test "should restore a deregistered database when the registering database instance has system replication disabled, without database instance leftovers" do + test "should restore a sap system when abap/messageserver instances are present" do sap_system_id = UUID.uuid4() - primary_database_host_id = UUID.uuid4() - secondary_database_host_id = UUID.uuid4() + database_host_id = UUID.uuid4() deregistered_at = DateTime.utc_now() - db_instance_number_1 = "00" - db_instance_number_2 = "01" - - db_sid = fake_sid() application_sid = fake_sid() message_server_host_id = UUID.uuid4() @@ -2330,27 +1354,6 @@ defmodule Trento.SapSystems.SapSystemTest do abap_instance_number = "01" initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: db_sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: primary_database_host_id, - sid: db_sid, - instance_number: db_instance_number_1, - system_replication: "Primary" - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: secondary_database_host_id, - instance_number: db_instance_number_2, - system_replication: "Secondary", - sid: db_sid - ), build( :application_instance_registered_event, sap_system_id: sap_system_id, @@ -2372,95 +1375,63 @@ defmodule Trento.SapSystems.SapSystemTest do sap_system_id: sap_system_id, sid: application_sid ), - build(:database_instance_deregistered_event, - sap_system_id: sap_system_id, - host_id: primary_database_host_id, - instance_number: db_instance_number_1, - deregistered_at: deregistered_at - ), - build(:database_instance_deregistered_event, - sap_system_id: sap_system_id, - host_id: secondary_database_host_id, - instance_number: db_instance_number_2, - deregistered_at: deregistered_at - ), - build(:database_deregistered_event, + build(:sap_system_deregistered_event, sap_system_id: sap_system_id, deregistered_at: deregistered_at ), - build(:sap_system_deregistered_event, + build(:application_instance_deregistered_event, sap_system_id: sap_system_id, - deregistered_at: deregistered_at + deregistered_at: deregistered_at, + instance_number: message_server_instance_number, + host_id: message_server_host_id ) ] - %{features: features, instance_number: instance_number, health: health} = - command = - build(:register_database_instance_command, - system_replication: nil, - sid: db_sid, - sap_system_id: sap_system_id + command = + build( + :register_application_instance_command, + sap_system_id: sap_system_id, + sid: application_sid, + db_host: database_host_id, + features: "MESSAGESERVER" ) assert_events_and_state( initial_events, command, [ - %DatabaseInstanceRegistered{ + %ApplicationInstanceRegistered{ sap_system_id: sap_system_id, - sid: db_sid, - tenant: command.tenant, + sid: application_sid, + host_id: command.host_id, instance_number: command.instance_number, instance_hostname: command.instance_hostname, features: command.features, http_port: command.http_port, https_port: command.https_port, start_priority: command.start_priority, - host_id: command.host_id, - system_replication: command.system_replication, - system_replication_status: command.system_replication_status, health: command.health }, - %DatabaseRestored{ + %SapSystemRestored{ sap_system_id: sap_system_id, + tenant: command.tenant, + db_host: command.db_host, health: command.health } ], fn sap_system -> - assert Kernel.length(sap_system.database.instances) == 1 - assert %SapSystem{ - deregistered_at: ^deregistered_at, - database: %Database{ - deregistered_at: nil, - sid: ^db_sid, - instances: [ - %Instance{ - sid: ^db_sid, - instance_number: ^instance_number, - features: ^features, - health: ^health, - system_replication: nil - } - ] - } + deregistered_at: nil } = sap_system end ) end - test "should restore a deregistered database when the registering database instance is a primary, without database instance leftovers" do + test "should reject all the commands except for the registration/instance deregistration ones, when the SAP system is deregistered" do sap_system_id = UUID.uuid4() - primary_database_host_id = UUID.uuid4() - secondary_database_host_id = UUID.uuid4() - deregistered_at = DateTime.utc_now() - db_instance_number_1 = "00" - db_instance_number_2 = "01" - - db_sid = fake_sid() application_sid = fake_sid() message_server_host_id = UUID.uuid4() @@ -2469,27 +1440,6 @@ defmodule Trento.SapSystems.SapSystemTest do abap_instance_number = "01" initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: db_sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: primary_database_host_id, - sid: db_sid, - instance_number: db_instance_number_1, - system_replication: "Primary" - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: secondary_database_host_id, - instance_number: db_instance_number_2, - system_replication: "Secondary", - sid: db_sid - ), build( :application_instance_registered_event, sap_system_id: sap_system_id, @@ -2511,1277 +1461,97 @@ defmodule Trento.SapSystems.SapSystemTest do sap_system_id: sap_system_id, sid: application_sid ), - build(:database_instance_deregistered_event, - sap_system_id: sap_system_id, - host_id: primary_database_host_id, - instance_number: db_instance_number_1, - deregistered_at: deregistered_at - ), - build(:database_instance_deregistered_event, - sap_system_id: sap_system_id, - host_id: secondary_database_host_id, - instance_number: db_instance_number_2, - deregistered_at: deregistered_at - ), - build(:database_deregistered_event, - sap_system_id: sap_system_id, - deregistered_at: deregistered_at - ), build(:sap_system_deregistered_event, sap_system_id: sap_system_id, deregistered_at: deregistered_at ) ] - %{features: features, instance_number: instance_number, health: health} = - command = - build(:register_database_instance_command, - system_replication: "Primary", - sid: db_sid, - sap_system_id: sap_system_id - ) + commands_to_accept = [ + build(:register_application_instance_command), + build(:rollup_sap_system_command) + ] + + for command <- commands_to_accept do + assert match?({:ok, _, _}, aggregate_run(initial_events, command)), + "Command #{inspect(command)} should be accepted by a deregistered SAP system" + end + end + + test "should deregister an ENQREP Application Instance, SAP system registered" do + sap_system_id = UUID.uuid4() + deregistered_at = DateTime.utc_now() + + message_server_host_id = UUID.uuid4() + abap_host_id = UUID.uuid4() + enqrep_host_id = UUID.uuid4() + + message_server_instance_number = "01" + abap_instance_number = "02" + enqrep_server_instance_number = "03" + + application_sid = fake_sid() assert_events_and_state( - initial_events, - command, [ - %DatabaseInstanceRegistered{ + build( + :application_instance_registered_event, sap_system_id: sap_system_id, - sid: db_sid, - tenant: command.tenant, - instance_number: command.instance_number, - instance_hostname: command.instance_hostname, - features: command.features, - http_port: command.http_port, - https_port: command.https_port, - start_priority: command.start_priority, - host_id: command.host_id, - system_replication: command.system_replication, - system_replication_status: command.system_replication_status, - health: command.health - }, - %DatabaseRestored{ + features: "MESSAGESERVER|ENQUE", + sid: application_sid, + host_id: message_server_host_id, + instance_number: message_server_instance_number + ), + build( + :application_instance_registered_event, sap_system_id: sap_system_id, - health: command.health + features: "ABAP|GATEWAY|ICMAN|IGS", + sid: application_sid, + host_id: abap_host_id, + instance_number: abap_instance_number + ), + build( + :sap_system_registered_event, + sap_system_id: sap_system_id, + sid: application_sid + ), + build( + :application_instance_registered_event, + sap_system_id: sap_system_id, + host_id: enqrep_host_id, + instance_number: enqrep_server_instance_number, + sid: application_sid, + features: "ENQREP" + ) + ], + %DeregisterApplicationInstance{ + sap_system_id: sap_system_id, + host_id: enqrep_host_id, + instance_number: enqrep_server_instance_number, + deregistered_at: deregistered_at + }, + [ + %ApplicationInstanceDeregistered{ + sap_system_id: sap_system_id, + host_id: enqrep_host_id, + instance_number: enqrep_server_instance_number, + deregistered_at: deregistered_at } ], fn sap_system -> - assert Kernel.length(sap_system.database.instances) == 1 - assert %SapSystem{ - deregistered_at: ^deregistered_at, - database: %Database{ - deregistered_at: nil, - sid: ^db_sid, - instances: [ - %Instance{ - sid: ^db_sid, - instance_number: ^instance_number, - features: ^features, - health: ^health, - system_replication: "Primary" - } - ] - } - } = sap_system - end - ) - end - - test "should restore a deregistered database when the registering database instance is a primary, with database instance leftovers" do - sap_system_id = UUID.uuid4() - - primary_database_host_id = UUID.uuid4() - secondary_database_host_id = UUID.uuid4() - - deregistered_at = DateTime.utc_now() - - db_instance_number_1 = "00" - db_instance_number_2 = "01" - - db_sid = fake_sid() - application_sid = fake_sid() - - message_server_host_id = UUID.uuid4() - message_server_instance_number = "00" - abap_host_id = UUID.uuid4() - abap_instance_number = "01" - - initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: db_sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: primary_database_host_id, - sid: db_sid, - instance_number: db_instance_number_1, - system_replication: "Primary" - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: secondary_database_host_id, - instance_number: db_instance_number_2, - system_replication: "Secondary", - sid: db_sid - ), - build( - :application_instance_registered_event, - sap_system_id: sap_system_id, - features: "MESSAGESERVER|ENQUE", - host_id: message_server_host_id, - instance_number: message_server_instance_number, - sid: application_sid - ), - build( - :application_instance_registered_event, - sap_system_id: sap_system_id, - features: "ABAP|GATEWAY|ICMAN|IGS", - host_id: abap_host_id, - instance_number: abap_instance_number, - sid: application_sid - ), - build( - :sap_system_registered_event, - sap_system_id: sap_system_id, - sid: application_sid - ), - build(:database_instance_deregistered_event, - sap_system_id: sap_system_id, - host_id: primary_database_host_id, - instance_number: db_instance_number_1, - deregistered_at: deregistered_at - ), - build(:database_deregistered_event, - sap_system_id: sap_system_id, - deregistered_at: deregistered_at - ), - build(:sap_system_deregistered_event, - sap_system_id: sap_system_id, - deregistered_at: deregistered_at - ) - ] - - %{features: features, instance_number: instance_number, health: health} = - command = - build(:register_database_instance_command, - system_replication: "Primary", - sid: db_sid, - sap_system_id: sap_system_id - ) - - assert_events_and_state( - initial_events, - command, - [ - %DatabaseInstanceRegistered{ - sap_system_id: sap_system_id, - sid: db_sid, - tenant: command.tenant, - instance_number: command.instance_number, - instance_hostname: command.instance_hostname, - features: command.features, - http_port: command.http_port, - https_port: command.https_port, - start_priority: command.start_priority, - host_id: command.host_id, - system_replication: command.system_replication, - system_replication_status: command.system_replication_status, - health: command.health - }, - %DatabaseRestored{ - sap_system_id: sap_system_id, - health: command.health - } - ], - fn sap_system -> - assert Kernel.length(sap_system.database.instances) == 2 - - assert %SapSystem{ - deregistered_at: ^deregistered_at, - database: %Database{ - deregistered_at: nil, - sid: ^db_sid, - instances: [ - %Instance{ - sid: ^db_sid, - instance_number: ^instance_number, - features: ^features, - health: ^health, - system_replication: "Primary" - }, - %Instance{} - ] - } - } = sap_system - end - ) - end - - test "should not restore a sap system when no abap/messageserver instances are present" do - sap_system_id = UUID.uuid4() - - primary_database_host_id = UUID.uuid4() - secondary_database_host_id = UUID.uuid4() - - deregistered_at = DateTime.utc_now() - - db_instance_number_1 = "00" - db_instance_number_2 = "01" - - db_sid = fake_sid() - application_sid = fake_sid() - - message_server_host_id = UUID.uuid4() - message_server_instance_number = "00" - abap_host_id = UUID.uuid4() - abap_instance_number = "01" - - initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: db_sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: primary_database_host_id, - sid: db_sid, - instance_number: db_instance_number_1, - system_replication: "Primary" - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: secondary_database_host_id, - instance_number: db_instance_number_2, - system_replication: "Secondary", - sid: db_sid - ), - build( - :application_instance_registered_event, - sap_system_id: sap_system_id, - features: "MESSAGESERVER|ENQUE", - host_id: message_server_host_id, - instance_number: message_server_instance_number, - sid: application_sid - ), - build( - :application_instance_registered_event, - sap_system_id: sap_system_id, - features: "ABAP|GATEWAY|ICMAN|IGS", - host_id: abap_host_id, - instance_number: abap_instance_number, - sid: application_sid - ), - build( - :sap_system_registered_event, - sap_system_id: sap_system_id, - sid: application_sid - ), - build(:database_instance_deregistered_event, - sap_system_id: sap_system_id, - host_id: primary_database_host_id, - instance_number: db_instance_number_1, - deregistered_at: deregistered_at - ), - build(:database_deregistered_event, - sap_system_id: sap_system_id, - deregistered_at: deregistered_at - ), - build(:sap_system_deregistered_event, - sap_system_id: sap_system_id, - deregistered_at: deregistered_at - ), - build(:application_instance_deregistered_event, - sap_system_id: sap_system_id, - deregistered_at: deregistered_at, - instance_number: message_server_instance_number, - host_id: message_server_host_id - ), - build(:database_instance_registered_event, - system_replication: "Primary", - sid: db_sid, - sap_system_id: sap_system_id - ), - build(:database_restored_event, - sap_system_id: sap_system_id - ) - ] - - command = - build( - :register_application_instance_command, - sap_system_id: sap_system_id, - sid: application_sid, - db_host: primary_database_host_id, - features: "IGS" - ) - - assert_events_and_state( - initial_events, - command, - [ - %ApplicationInstanceRegistered{ - sap_system_id: sap_system_id, - sid: application_sid, - host_id: command.host_id, - instance_number: command.instance_number, - instance_hostname: command.instance_hostname, - features: command.features, - http_port: command.http_port, - https_port: command.https_port, - start_priority: command.start_priority, - health: command.health - } - ], - fn sap_system -> - assert %SapSystem{ - deregistered_at: ^deregistered_at, - database: %Database{ - deregistered_at: nil, - sid: ^db_sid - } - } = sap_system - end - ) - end - - test "should restore a sap system when abap/messageserver instances are present" do - sap_system_id = UUID.uuid4() - - primary_database_host_id = UUID.uuid4() - secondary_database_host_id = UUID.uuid4() - - deregistered_at = DateTime.utc_now() - - db_instance_number_1 = "00" - db_instance_number_2 = "01" - - db_sid = fake_sid() - application_sid = fake_sid() - - message_server_host_id = UUID.uuid4() - message_server_instance_number = "00" - abap_host_id = UUID.uuid4() - abap_instance_number = "01" - - initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: db_sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: primary_database_host_id, - sid: db_sid, - instance_number: db_instance_number_1, - system_replication: "Primary" - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: secondary_database_host_id, - instance_number: db_instance_number_2, - system_replication: "Secondary", - sid: db_sid - ), - build( - :application_instance_registered_event, - sap_system_id: sap_system_id, - features: "MESSAGESERVER|ENQUE", - host_id: message_server_host_id, - instance_number: message_server_instance_number, - sid: application_sid - ), - build( - :application_instance_registered_event, - sap_system_id: sap_system_id, - features: "ABAP|GATEWAY|ICMAN|IGS", - host_id: abap_host_id, - instance_number: abap_instance_number, - sid: application_sid - ), - build( - :sap_system_registered_event, - sap_system_id: sap_system_id, - sid: application_sid - ), - build(:database_instance_deregistered_event, - sap_system_id: sap_system_id, - host_id: primary_database_host_id, - instance_number: db_instance_number_1, - deregistered_at: deregistered_at - ), - build(:database_deregistered_event, - sap_system_id: sap_system_id, - deregistered_at: deregistered_at - ), - build(:sap_system_deregistered_event, - sap_system_id: sap_system_id, - deregistered_at: deregistered_at - ), - build(:application_instance_deregistered_event, - sap_system_id: sap_system_id, - deregistered_at: deregistered_at, - instance_number: message_server_instance_number, - host_id: message_server_host_id - ), - build(:database_instance_registered_event, - system_replication: "Primary", - sid: db_sid, - sap_system_id: sap_system_id - ), - build(:database_restored_event, - sap_system_id: sap_system_id - ) - ] - - command = - build( - :register_application_instance_command, - sap_system_id: sap_system_id, - sid: application_sid, - db_host: primary_database_host_id, - features: "MESSAGESERVER" - ) - - assert_events_and_state( - initial_events, - command, - [ - %ApplicationInstanceRegistered{ - sap_system_id: sap_system_id, - sid: application_sid, - host_id: command.host_id, - instance_number: command.instance_number, - instance_hostname: command.instance_hostname, - features: command.features, - http_port: command.http_port, - https_port: command.https_port, - start_priority: command.start_priority, - health: command.health - }, - %SapSystemRestored{ - sap_system_id: sap_system_id, - tenant: command.tenant, - db_host: command.db_host, - health: command.health - } - ], - fn sap_system -> - assert %SapSystem{ - deregistered_at: nil, - database: %Database{ - deregistered_at: nil, - sid: ^db_sid - } - } = sap_system - end - ) - end - - test "should not restore a sap system if the database is not present and messageserver/abap instance are present" do - sap_system_id = UUID.uuid4() - - primary_database_host_id = UUID.uuid4() - secondary_database_host_id = UUID.uuid4() - - deregistered_at = DateTime.utc_now() - - db_instance_number_1 = "00" - db_instance_number_2 = "01" - - db_sid = fake_sid() - application_sid = fake_sid() - - message_server_host_id = UUID.uuid4() - message_server_instance_number = "00" - abap_host_id = UUID.uuid4() - abap_instance_number = "01" - - initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: db_sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: primary_database_host_id, - sid: db_sid, - instance_number: db_instance_number_1, - system_replication: "Primary" - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: secondary_database_host_id, - instance_number: db_instance_number_2, - system_replication: "Secondary", - sid: db_sid - ), - build( - :application_instance_registered_event, - sap_system_id: sap_system_id, - features: "MESSAGESERVER|ENQUE", - host_id: message_server_host_id, - instance_number: message_server_instance_number, - sid: application_sid - ), - build( - :application_instance_registered_event, - sap_system_id: sap_system_id, - features: "ABAP|GATEWAY|ICMAN|IGS", - host_id: abap_host_id, - instance_number: abap_instance_number, - sid: application_sid - ), - build( - :sap_system_registered_event, - sap_system_id: sap_system_id, - sid: application_sid - ), - build(:database_instance_deregistered_event, - sap_system_id: sap_system_id, - host_id: primary_database_host_id, - instance_number: db_instance_number_1, - deregistered_at: deregistered_at - ), - build(:database_deregistered_event, - sap_system_id: sap_system_id, - deregistered_at: deregistered_at - ), - build(:sap_system_deregistered_event, - sap_system_id: sap_system_id, - deregistered_at: deregistered_at - ), - build(:application_instance_deregistered_event, - sap_system_id: sap_system_id, - deregistered_at: deregistered_at, - instance_number: message_server_instance_number, - host_id: message_server_host_id - ) - ] - - command = - build( - :register_application_instance_command, - sap_system_id: sap_system_id, - sid: application_sid, - db_host: primary_database_host_id, - features: "MESSAGESERVER" - ) - - assert_events_and_state( - initial_events, - command, - [ - %ApplicationInstanceRegistered{ - sap_system_id: sap_system_id, - sid: application_sid, - host_id: command.host_id, - instance_number: command.instance_number, - instance_hostname: command.instance_hostname, - features: command.features, - http_port: command.http_port, - https_port: command.https_port, - start_priority: command.start_priority, - health: command.health - } - ], - fn sap_system -> - assert %SapSystem{ - deregistered_at: ^deregistered_at, - database: %Database{ - deregistered_at: ^deregistered_at, - sid: ^db_sid - } - } = sap_system - end - ) - end - - test "should reject all the commands except for the registration/instance deregistration ones, when the SAP system is deregistered" do - sap_system_id = UUID.uuid4() - - primary_database_host_id = UUID.uuid4() - secondary_database_host_id = UUID.uuid4() - - deregistered_at = DateTime.utc_now() - - db_instance_number_1 = "00" - db_instance_number_2 = "01" - - db_sid = fake_sid() - application_sid = fake_sid() - - message_server_host_id = UUID.uuid4() - message_server_instance_number = "00" - abap_host_id = UUID.uuid4() - abap_instance_number = "01" - - initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: db_sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: primary_database_host_id, - sid: db_sid, - instance_number: db_instance_number_1, - system_replication: "Primary" - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: secondary_database_host_id, - instance_number: db_instance_number_2, - system_replication: "Secondary", - sid: db_sid - ), - build( - :application_instance_registered_event, - sap_system_id: sap_system_id, - features: "MESSAGESERVER|ENQUE", - host_id: message_server_host_id, - instance_number: message_server_instance_number, - sid: application_sid - ), - build( - :application_instance_registered_event, - sap_system_id: sap_system_id, - features: "ABAP|GATEWAY|ICMAN|IGS", - host_id: abap_host_id, - instance_number: abap_instance_number, - sid: application_sid - ), - build( - :sap_system_registered_event, - sap_system_id: sap_system_id, - sid: application_sid - ), - build(:database_instance_deregistered_event, - sap_system_id: sap_system_id, - host_id: primary_database_host_id, - instance_number: db_instance_number_1, - deregistered_at: deregistered_at - ), - build(:database_deregistered_event, - sap_system_id: sap_system_id, - deregistered_at: deregistered_at - ), - build(:sap_system_deregistered_event, - sap_system_id: sap_system_id, - deregistered_at: deregistered_at - ) - ] - - commands_to_accept = [ - build(:register_database_instance_command), - build(:register_application_instance_command), - build(:rollup_sap_system_command) - ] - - for command <- commands_to_accept do - assert match?({:ok, _, _}, aggregate_run(initial_events, command)), - "Command #{inspect(command)} should be accepted by a deregistered SAP system" - end - end - - test "should deregister a Database and SAP system when the Primary database instance is removed" do - sap_system_id = UUID.uuid4() - - primary_database_host_id = UUID.uuid4() - secondary_database_host_id = UUID.uuid4() - - deregistered_at = DateTime.utc_now() - - db_instance_number_1 = "00" - db_instance_number_2 = "01" - - db_sid = fake_sid() - application_sid = fake_sid() - - message_server_host_id = UUID.uuid4() - message_server_instance_number = "00" - abap_host_id = UUID.uuid4() - abap_instance_number = "01" - - assert_events_and_state( - [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: db_sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: primary_database_host_id, - sid: db_sid, - instance_number: db_instance_number_1, - system_replication: "Primary" - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: secondary_database_host_id, - instance_number: db_instance_number_2, - system_replication: "Secondary", - sid: db_sid - ), - build( - :application_instance_registered_event, - sap_system_id: sap_system_id, - features: "MESSAGESERVER|ENQUE", - host_id: message_server_host_id, - instance_number: message_server_instance_number, - sid: application_sid - ), - build( - :application_instance_registered_event, - sap_system_id: sap_system_id, - features: "ABAP|GATEWAY|ICMAN|IGS", - host_id: abap_host_id, - instance_number: abap_instance_number, - sid: application_sid - ), - build( - :sap_system_registered_event, - sap_system_id: sap_system_id, - sid: application_sid - ) - ], - %DeregisterDatabaseInstance{ - sap_system_id: sap_system_id, - host_id: primary_database_host_id, - instance_number: db_instance_number_1, - deregistered_at: deregistered_at - }, - [ - %DatabaseInstanceDeregistered{ - sap_system_id: sap_system_id, - host_id: primary_database_host_id, - instance_number: db_instance_number_1, - deregistered_at: deregistered_at - }, - %DatabaseDeregistered{ - sap_system_id: sap_system_id, - deregistered_at: deregistered_at - }, - %SapSystemDeregistered{ - sap_system_id: sap_system_id, - deregistered_at: deregistered_at - } - ], - fn sap_system -> - assert %SapSystem{ - sid: ^application_sid, - database: %Database{ - sid: ^db_sid, - instances: [ - %Instance{ - instance_number: ^db_instance_number_2, - sid: ^db_sid, - host_id: ^secondary_database_host_id - } - ], - health: :passing, - deregistered_at: ^deregistered_at - }, - application: %Application{ - sid: ^application_sid, - instances: [ - %Instance{instance_number: ^abap_instance_number, sid: ^application_sid}, - %Instance{ - instance_number: ^message_server_instance_number, - sid: ^application_sid - } - ] - }, - deregistered_at: ^deregistered_at - } = sap_system - end - ) - end - - test "should deregister a secondary DB instance, no SAP system registered." do - sap_system_id = UUID.uuid4() - deregistered_at = DateTime.utc_now() - - instance_number_1 = "00" - instance_number_2 = "01" - - db_sid = fake_sid() - - primary_db_host_id = UUID.uuid4() - secondary_db_host_id = UUID.uuid4() - - assert_events_and_state( - [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: db_sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - system_replication: "Primary", - sid: db_sid, - instance_number: instance_number_1, - host_id: primary_db_host_id - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - system_replication: "Secondary", - sid: db_sid, - host_id: secondary_db_host_id, - instance_number: instance_number_2 - ) - ], - %DeregisterDatabaseInstance{ - sap_system_id: sap_system_id, - host_id: secondary_db_host_id, - instance_number: instance_number_2, - deregistered_at: deregistered_at - }, - %DatabaseInstanceDeregistered{ - sap_system_id: sap_system_id, - host_id: secondary_db_host_id, - instance_number: instance_number_2, - deregistered_at: deregistered_at - }, - fn sap_system -> - assert %SapSystem{ - sid: nil, - database: %Database{ - sid: ^db_sid, - deregistered_at: nil, - instances: [%Instance{instance_number: ^instance_number_1}] - } - } = sap_system - end - ) - end - - test "should deregister the only database instance and deregister the entire database, no SAP system registered, system replication disabled" do - sap_system_id = UUID.uuid4() - database_host_id = UUID.uuid4() - deregistered_at = DateTime.utc_now() - db_instance_number_1 = "00" - db_sid = fake_sid() - - assert_events_and_state( - [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: db_sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: database_host_id, - instance_number: db_instance_number_1, - system_replication: nil, - sid: db_sid - ) - ], - %DeregisterDatabaseInstance{ - sap_system_id: sap_system_id, - host_id: database_host_id, - instance_number: db_instance_number_1, - deregistered_at: deregistered_at - }, - [ - %DatabaseInstanceDeregistered{ - sap_system_id: sap_system_id, - host_id: database_host_id, - instance_number: db_instance_number_1, - deregistered_at: deregistered_at - }, - %DatabaseDeregistered{ - sap_system_id: sap_system_id, - deregistered_at: deregistered_at - } - ], - fn sap_system -> - assert %SapSystem{ - sid: nil, - database: %Database{ - sid: ^db_sid, - instances: [], - health: :passing, - deregistered_at: ^deregistered_at - }, - application: nil, - deregistered_at: nil - } = sap_system - end - ) - end - - test "should deregister a single DB instance of two if no SR enabled, SAP system not registered" do - sap_system_id = UUID.uuid4() - database_host_id = UUID.uuid4() - second_database_host_id = UUID.uuid4() - deregistered_at = DateTime.utc_now() - db_instance_number_1 = "00" - db_instance_number_2 = "01" - - db_sid = fake_sid() - - assert_events_and_state( - [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: db_sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: database_host_id, - instance_number: db_instance_number_1, - system_replication: nil, - sid: db_sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: second_database_host_id, - instance_number: db_instance_number_2, - system_replication: nil, - sid: db_sid - ) - ], - %DeregisterDatabaseInstance{ - sap_system_id: sap_system_id, - host_id: database_host_id, - instance_number: db_instance_number_1, - deregistered_at: deregistered_at - }, - %DatabaseInstanceDeregistered{ - sap_system_id: sap_system_id, - host_id: database_host_id, - instance_number: db_instance_number_1, - deregistered_at: deregistered_at - }, - fn sap_system -> - assert %SapSystem{ - database: %Database{ - sid: ^db_sid, - deregistered_at: nil, - instances: [%Instance{instance_number: ^db_instance_number_2}] - } - } = sap_system - end - ) - end - - test "should deregister the primary instance, the entire database and then the secondary instance, SAP system not registered" do - sap_system_id = UUID.uuid4() - primary_database_host_id = UUID.uuid4() - secondary_database_host_id = UUID.uuid4() - deregistered_at = DateTime.utc_now() - db_instance_number_1 = "00" - db_instance_number_2 = "01" - - db_sid = fake_sid() - - initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: db_sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: primary_database_host_id, - sid: db_sid, - instance_number: db_instance_number_1, - system_replication: "Primary" - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: secondary_database_host_id, - instance_number: db_instance_number_2, - system_replication: "Secondary" - ) - ] - - assert_events( - initial_events, - [ - %DeregisterDatabaseInstance{ - sap_system_id: sap_system_id, - host_id: primary_database_host_id, - instance_number: db_instance_number_1, - deregistered_at: deregistered_at - }, - %DeregisterDatabaseInstance{ - sap_system_id: sap_system_id, - host_id: secondary_database_host_id, - instance_number: db_instance_number_2, - deregistered_at: deregistered_at - } - ], - [ - %DatabaseInstanceDeregistered{ - sap_system_id: sap_system_id, - host_id: primary_database_host_id, - instance_number: db_instance_number_1, - deregistered_at: deregistered_at - }, - %DatabaseDeregistered{ - sap_system_id: sap_system_id, - deregistered_at: deregistered_at - }, - %DatabaseInstanceDeregistered{ - sap_system_id: sap_system_id, - host_id: secondary_database_host_id, - instance_number: db_instance_number_2, - deregistered_at: deregistered_at - } - ] - ) - end - - test "should correctly deregister the database in a scale out scenario, with two primary and two secondary, no SAP system registered" do - sap_system_id = UUID.uuid4() - first_primary_database_host_id = UUID.uuid4() - other_primary_database_host_id = UUID.uuid4() - - secondary_database_host_id = UUID.uuid4() - other_secondary_database_host_id = UUID.uuid4() - - deregistered_at = DateTime.utc_now() - - db_instance_number_1 = "00" - db_instance_number_2 = "01" - db_instance_number_3 = "02" - db_instance_number_4 = "03" - - db_sid = fake_sid() - - initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: db_sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: first_primary_database_host_id, - sid: db_sid, - instance_number: db_instance_number_1, - system_replication: "Primary" - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: other_primary_database_host_id, - sid: db_sid, - instance_number: db_instance_number_2, - system_replication: "Primary" - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: secondary_database_host_id, - instance_number: db_instance_number_3, - system_replication: "Secondary" - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: other_secondary_database_host_id, - instance_number: db_instance_number_4, - system_replication: "Secondary" - ) - ] - - assert_events( - initial_events, - [ - %DeregisterDatabaseInstance{ - sap_system_id: sap_system_id, - host_id: first_primary_database_host_id, - instance_number: db_instance_number_1, - deregistered_at: deregistered_at - }, - %DeregisterDatabaseInstance{ - sap_system_id: sap_system_id, - host_id: other_primary_database_host_id, - instance_number: db_instance_number_2, - deregistered_at: deregistered_at - }, - %DeregisterDatabaseInstance{ - sap_system_id: sap_system_id, - host_id: secondary_database_host_id, - instance_number: db_instance_number_3, - deregistered_at: deregistered_at - }, - %DeregisterDatabaseInstance{ - sap_system_id: sap_system_id, - host_id: other_secondary_database_host_id, - instance_number: db_instance_number_4, - deregistered_at: deregistered_at - } - ], - [ - %DatabaseInstanceDeregistered{ - sap_system_id: sap_system_id, - host_id: first_primary_database_host_id, - instance_number: db_instance_number_1, - deregistered_at: deregistered_at - }, - %DatabaseInstanceDeregistered{ - sap_system_id: sap_system_id, - host_id: other_primary_database_host_id, - instance_number: db_instance_number_2, - deregistered_at: deregistered_at - }, - %DatabaseDeregistered{ - sap_system_id: sap_system_id, - deregistered_at: deregistered_at - }, - %DatabaseInstanceDeregistered{ - sap_system_id: sap_system_id, - host_id: secondary_database_host_id, - instance_number: db_instance_number_3, - deregistered_at: deregistered_at - }, - %DatabaseInstanceDeregistered{ - sap_system_id: sap_system_id, - host_id: other_secondary_database_host_id, - instance_number: db_instance_number_4, - deregistered_at: deregistered_at - } - ] - ) - end - - test "should deregister an ENQREP Application Instance, SAP system registered" do - sap_system_id = UUID.uuid4() - deregistered_at = DateTime.utc_now() - - database_host_id = UUID.uuid4() - message_server_host_id = UUID.uuid4() - abap_host_id = UUID.uuid4() - enqrep_host_id = UUID.uuid4() - - database_instance_number = "00" - message_server_instance_number = "01" - abap_instance_number = "02" - enqrep_server_instance_number = "03" - - db_sid = fake_sid() - application_sid = fake_sid() - - assert_events_and_state( - [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: db_sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: database_host_id, - sid: db_sid, - instance_number: database_instance_number, - system_replication: nil - ), - build( - :application_instance_registered_event, - sap_system_id: sap_system_id, - features: "MESSAGESERVER|ENQUE", - sid: application_sid, - host_id: message_server_host_id, - instance_number: message_server_instance_number - ), - build( - :application_instance_registered_event, - sap_system_id: sap_system_id, - features: "ABAP|GATEWAY|ICMAN|IGS", - sid: application_sid, - host_id: abap_host_id, - instance_number: abap_instance_number - ), - build( - :sap_system_registered_event, - sap_system_id: sap_system_id, - sid: application_sid - ), - build( - :application_instance_registered_event, - sap_system_id: sap_system_id, - host_id: enqrep_host_id, - instance_number: enqrep_server_instance_number, - sid: application_sid, - features: "ENQREP" - ) - ], - %DeregisterApplicationInstance{ - sap_system_id: sap_system_id, - host_id: enqrep_host_id, - instance_number: enqrep_server_instance_number, - deregistered_at: deregistered_at - }, - [ - %ApplicationInstanceDeregistered{ - sap_system_id: sap_system_id, - host_id: enqrep_host_id, - instance_number: enqrep_server_instance_number, - deregistered_at: deregistered_at - } - ], - fn sap_system -> - assert %SapSystem{ - sid: ^application_sid, - deregistered_at: nil, - database: %Database{ - sid: ^db_sid, - deregistered_at: nil, - instances: [ - %Instance{ - instance_number: ^database_instance_number, - host_id: ^database_host_id - } - ] - }, - application: %Application{ - sid: ^application_sid, - instances: [ - %Instance{ - host_id: ^abap_host_id, - instance_number: ^abap_instance_number - }, - %Instance{ - host_id: ^message_server_host_id, - instance_number: ^message_server_instance_number - } - ] - } + sid: ^application_sid, + deregistered_at: nil, + instances: [ + %Instance{ + host_id: ^abap_host_id, + instance_number: ^abap_instance_number + }, + %Instance{ + host_id: ^message_server_host_id, + instance_number: ^message_server_instance_number + } + ] } = sap_system end ) @@ -3792,15 +1562,12 @@ defmodule Trento.SapSystems.SapSystemTest do deregistered_at = DateTime.utc_now() application_sid = fake_sid() - db_sid = fake_sid() - database_host_id = UUID.uuid4() message_server_host_id = UUID.uuid4() abap_host_id = UUID.uuid4() abap_2_host_id = UUID.uuid4() enqrep_host_id = UUID.uuid4() - database_instance_number = "00" message_server_instance_number = "01" abap_instance_number = "02" abap_2_instance_number = "03" @@ -3808,19 +1575,6 @@ defmodule Trento.SapSystems.SapSystemTest do assert_events_and_state( [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: db_sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: database_host_id, - sid: db_sid, - instance_number: database_instance_number, - system_replication: nil - ), build( :application_instance_registered_event, sap_system_id: sap_system_id, @@ -3877,33 +1631,20 @@ defmodule Trento.SapSystems.SapSystemTest do assert %SapSystem{ sid: ^application_sid, deregistered_at: nil, - database: %Database{ - sid: ^db_sid, - deregistered_at: nil, - instances: [ - %Instance{ - instance_number: ^database_instance_number, - host_id: ^database_host_id - } - ] - }, - application: %Application{ - sid: ^application_sid, - instances: [ - %Instance{ - host_id: ^enqrep_host_id, - instance_number: ^enqrep_server_instance_number - }, - %Instance{ - host_id: ^abap_host_id, - instance_number: ^abap_instance_number - }, - %Instance{ - host_id: ^message_server_host_id, - instance_number: ^message_server_instance_number - } - ] - } + instances: [ + %Instance{ + host_id: ^enqrep_host_id, + instance_number: ^enqrep_server_instance_number + }, + %Instance{ + host_id: ^abap_host_id, + instance_number: ^abap_instance_number + }, + %Instance{ + host_id: ^message_server_host_id, + instance_number: ^message_server_instance_number + } + ] } = sap_system end ) @@ -3912,33 +1653,18 @@ defmodule Trento.SapSystems.SapSystemTest do test "should deregister last ABAP Application Instance and deregister SAP System" do sap_system_id = UUID.uuid4() deregistered_at = DateTime.utc_now() - db_sid = fake_sid() application_sid = fake_sid() - database_host_id = UUID.uuid4() message_server_host_id = UUID.uuid4() abap_host_id = UUID.uuid4() enqrep_host_id = UUID.uuid4() - database_instance_number = "00" message_server_instance_number = "01" abap_instance_number = "02" enqrep_server_instance_number = "03" assert_events_and_state( [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: db_sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: database_host_id, - sid: db_sid, - instance_number: database_instance_number - ), build( :application_instance_registered_event, sap_system_id: sap_system_id, @@ -3990,28 +1716,16 @@ defmodule Trento.SapSystems.SapSystemTest do fn sap_system -> assert %SapSystem{ sid: ^application_sid, - database: %Database{ - deregistered_at: nil, - sid: ^db_sid, - instances: [ - %Instance{ - instance_number: ^database_instance_number, - host_id: ^database_host_id - } - ] - }, - application: %Application{ - instances: [ - %Instance{ - instance_number: ^enqrep_server_instance_number, - host_id: ^enqrep_host_id - }, - %Instance{ - instance_number: ^message_server_instance_number, - host_id: ^message_server_host_id - } - ] - }, + instances: [ + %Instance{ + instance_number: ^enqrep_server_instance_number, + host_id: ^enqrep_host_id + }, + %Instance{ + instance_number: ^message_server_instance_number, + host_id: ^message_server_host_id + } + ], deregistered_at: ^deregistered_at } = sap_system end @@ -4022,354 +1736,81 @@ defmodule Trento.SapSystems.SapSystemTest do sap_system_id = UUID.uuid4() deregistered_at = DateTime.utc_now() - database_host_id = UUID.uuid4() message_server_host_id = UUID.uuid4() - database_instance_number = "00" message_server_instance_number = "01" application_sid = fake_sid() - database_sid = fake_sid() assert_events_and_state( [ - build( - :database_registered_event, - sid: database_sid, - sap_system_id: sap_system_id - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - sid: database_sid, - host_id: database_host_id, - instance_number: database_instance_number - ), build( :application_instance_registered_event, sap_system_id: sap_system_id, sid: application_sid, features: "MESSAGESERVER|ENQUE", - host_id: message_server_host_id, - instance_number: message_server_instance_number - ) - ], - %DeregisterApplicationInstance{ - sap_system_id: sap_system_id, - host_id: message_server_host_id, - instance_number: message_server_instance_number, - deregistered_at: deregistered_at - }, - %ApplicationInstanceDeregistered{ - sap_system_id: sap_system_id, - host_id: message_server_host_id, - instance_number: message_server_instance_number, - deregistered_at: deregistered_at - }, - fn sap_system -> - assert %SapSystem{ - sid: nil, - database: %Database{ - sid: ^database_sid, - deregistered_at: nil, - instances: [ - %Instance{ - instance_number: ^database_instance_number, - host_id: ^database_host_id - } - ] - }, - application: %Application{ - instances: [] - }, - deregistered_at: nil - } = sap_system - end - ) - end - - test "should deregister Message Server and deregister SAP System" do - sap_system_id = UUID.uuid4() - deregistered_at = DateTime.utc_now() - - database_host_id = UUID.uuid4() - message_server_host_id = UUID.uuid4() - abap_host_id = UUID.uuid4() - enqrep_host_id = UUID.uuid4() - - database_instance_number = "00" - message_server_instance_number = "01" - abap_instance_number = "02" - enqrep_server_instance_number = "03" - - db_sid = fake_sid() - application_sid = fake_sid() - - assert_events_and_state( - [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: db_sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: database_host_id, - instance_number: database_instance_number, - sid: db_sid - ), - build( - :application_instance_registered_event, - sap_system_id: sap_system_id, - features: "MESSAGESERVER|ENQUE", - host_id: message_server_host_id, - instance_number: message_server_instance_number, - sid: application_sid - ), - build( - :application_instance_registered_event, - sap_system_id: sap_system_id, - features: "ABAP|GATEWAY|ICMAN|IGS", - host_id: abap_host_id, - instance_number: abap_instance_number, - sid: application_sid - ), - build( - :sap_system_registered_event, - sap_system_id: sap_system_id, - sid: application_sid - ), - build( - :application_instance_registered_event, - sap_system_id: sap_system_id, - host_id: enqrep_host_id, - instance_number: enqrep_server_instance_number, - features: "ENQREP", - sid: application_sid - ) - ], - %DeregisterApplicationInstance{ - sap_system_id: sap_system_id, - host_id: message_server_host_id, - instance_number: message_server_instance_number, - deregistered_at: deregistered_at - }, - [ - %ApplicationInstanceDeregistered{ - sap_system_id: sap_system_id, - host_id: message_server_host_id, - instance_number: message_server_instance_number, - deregistered_at: deregistered_at - }, - %SapSystemDeregistered{ - sap_system_id: sap_system_id, - deregistered_at: deregistered_at - } - ], - fn sap_system -> - assert %SapSystem{ - database: %Database{ - sid: ^db_sid, - instances: [ - %Instance{ - instance_number: ^database_instance_number, - host_id: ^database_host_id - } - ] - }, - application: %Application{ - instances: [ - %Instance{ - host_id: ^enqrep_host_id, - instance_number: ^enqrep_server_instance_number - }, - %Instance{ - host_id: ^abap_host_id, - instance_number: ^abap_instance_number - } - ] - }, - deregistered_at: ^deregistered_at, - sid: ^application_sid - } = sap_system - end - ) - end - - test "should deregister the primary instance of database, the SAP system and deregister the ABAP application instance" do - sap_system_id = UUID.uuid4() - deregistered_at = DateTime.utc_now() - - primary_database_host_id = UUID.uuid4() - secondary_database_host_id = UUID.uuid4() - - message_server_host_id = UUID.uuid4() - abap_host_id = UUID.uuid4() - - database_instance_number_1 = "00" - database_instance_number_2 = "00" - - message_server_instance_number = "01" - abap_instance_number = "02" - - db_sid = fake_sid() - application_sid = fake_sid() - - initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: db_sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: primary_database_host_id, - sid: db_sid, - instance_number: database_instance_number_1, - system_replication: "Primary" - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - host_id: secondary_database_host_id, - instance_number: database_instance_number_2, - system_replication: "Secondary" - ), - build( - :application_instance_registered_event, - sap_system_id: sap_system_id, - features: "MESSAGESERVER|ENQUE", - sid: application_sid, - host_id: message_server_host_id, - instance_number: message_server_instance_number - ), - build( - :application_instance_registered_event, - sap_system_id: sap_system_id, - features: "ABAP|GATEWAY|ICMAN|IGS", - sid: application_sid, - host_id: abap_host_id, - instance_number: abap_instance_number - ), - build( - :sap_system_registered_event, - sap_system_id: sap_system_id, - sid: application_sid - ) - ] - - assert_events( - initial_events, - [ - %DeregisterDatabaseInstance{ - sap_system_id: sap_system_id, - host_id: primary_database_host_id, - instance_number: database_instance_number_1, - deregistered_at: deregistered_at - }, - %DeregisterApplicationInstance{ - sap_system_id: sap_system_id, - host_id: message_server_host_id, - instance_number: message_server_instance_number, - deregistered_at: deregistered_at - } - ], - [ - %DatabaseInstanceDeregistered{ - sap_system_id: sap_system_id, - host_id: primary_database_host_id, - instance_number: database_instance_number_1, - deregistered_at: deregistered_at - }, - %DatabaseDeregistered{ - sap_system_id: sap_system_id, - deregistered_at: deregistered_at - }, - %SapSystemDeregistered{ - sap_system_id: sap_system_id, - deregistered_at: deregistered_at - }, - %ApplicationInstanceDeregistered{ - sap_system_id: sap_system_id, - host_id: message_server_host_id, - instance_number: message_server_instance_number, - deregistered_at: deregistered_at - } - ] - ) - end - - test "should not deregister a not registered application instance" do - sap_system_id = UUID.uuid4() - db_sid = fake_sid() - - assert_error( - [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: db_sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - sid: db_sid, - host_id: UUID.uuid4(), - instance_number: "00", - system_replication: "Primary" + host_id: message_server_host_id, + instance_number: message_server_instance_number ) ], + %DeregisterApplicationInstance{ + sap_system_id: sap_system_id, + host_id: message_server_host_id, + instance_number: message_server_instance_number, + deregistered_at: deregistered_at + }, [ - %DeregisterApplicationInstance{ + %ApplicationInstanceDeregistered{ sap_system_id: sap_system_id, - host_id: UUID.uuid4(), - instance_number: "01", - deregistered_at: DateTime.utc_now() + host_id: message_server_host_id, + instance_number: message_server_instance_number, + deregistered_at: deregistered_at + }, + %SapSystemTombstoned{ + sap_system_id: sap_system_id } ], - {:error, :application_instance_not_registered} + fn sap_system -> + assert %SapSystem{ + sid: nil, + instances: [], + deregistered_at: nil + } = sap_system + end ) end - test "should not deregister an already deregistered application instance" do + test "should deregister Message Server and deregister SAP System" do sap_system_id = UUID.uuid4() - db_sid = fake_sid() + deregistered_at = DateTime.utc_now() + + message_server_host_id = UUID.uuid4() + abap_host_id = UUID.uuid4() + enqrep_host_id = UUID.uuid4() + + message_server_instance_number = "01" + abap_instance_number = "02" + enqrep_server_instance_number = "03" + application_sid = fake_sid() - deregistered_host_id = UUID.uuid4() - deregistered_instance_number = "02" - assert_error( + assert_events_and_state( [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: db_sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - sid: db_sid, - host_id: UUID.uuid4(), - instance_number: "00", - system_replication: "Primary" - ), build( :application_instance_registered_event, sap_system_id: sap_system_id, features: "MESSAGESERVER|ENQUE", - sid: application_sid, - host_id: UUID.uuid4(), - instance_number: "01" + host_id: message_server_host_id, + instance_number: message_server_instance_number, + sid: application_sid ), build( :application_instance_registered_event, sap_system_id: sap_system_id, features: "ABAP|GATEWAY|ICMAN|IGS", - sid: application_sid, - host_id: deregistered_host_id, - instance_number: deregistered_instance_number + host_id: abap_host_id, + instance_number: abap_instance_number, + sid: application_sid ), build( :sap_system_registered_event, @@ -4377,80 +1818,99 @@ defmodule Trento.SapSystems.SapSystemTest do sid: application_sid ), build( - :application_instance_deregistered_event, + :application_instance_registered_event, sap_system_id: sap_system_id, - host_id: deregistered_host_id, - instance_number: deregistered_instance_number, - deregistered_at: DateTime.utc_now() + host_id: enqrep_host_id, + instance_number: enqrep_server_instance_number, + features: "ENQREP", + sid: application_sid ) ], + %DeregisterApplicationInstance{ + sap_system_id: sap_system_id, + host_id: message_server_host_id, + instance_number: message_server_instance_number, + deregistered_at: deregistered_at + }, [ - %DeregisterApplicationInstance{ + %ApplicationInstanceDeregistered{ sap_system_id: sap_system_id, - host_id: deregistered_host_id, - instance_number: deregistered_instance_number, - deregistered_at: DateTime.utc_now() + host_id: message_server_host_id, + instance_number: message_server_instance_number, + deregistered_at: deregistered_at + }, + %SapSystemDeregistered{ + sap_system_id: sap_system_id, + deregistered_at: deregistered_at } ], - {:error, :application_instance_not_registered} + fn sap_system -> + assert %SapSystem{ + instances: [ + %Instance{ + host_id: ^enqrep_host_id, + instance_number: ^enqrep_server_instance_number + }, + %Instance{ + host_id: ^abap_host_id, + instance_number: ^abap_instance_number + } + ], + deregistered_at: ^deregistered_at, + sid: ^application_sid + } = sap_system + end ) end - test "should not deregister a not registered database instance" do + test "should not deregister a not registered application instance" do sap_system_id = UUID.uuid4() - db_sid = fake_sid() assert_error( + [], [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: db_sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - sid: db_sid, - host_id: UUID.uuid4(), - instance_number: "00", - system_replication: "Primary" - ) - ], - [ - %DeregisterDatabaseInstance{ + %DeregisterApplicationInstance{ sap_system_id: sap_system_id, host_id: UUID.uuid4(), instance_number: "01", deregistered_at: DateTime.utc_now() } ], - {:error, :database_instance_not_registered} + {:error, :sap_system_not_registered} ) end - test "should not deregister an already deregistered database instance" do + test "should not deregister an already deregistered application instance" do sap_system_id = UUID.uuid4() - db_sid = fake_sid() + application_sid = fake_sid() deregistered_host_id = UUID.uuid4() - deregistered_instance_number = "01" + deregistered_instance_number = "02" assert_error( [ build( - :database_registered_event, + :application_instance_registered_event, sap_system_id: sap_system_id, - sid: db_sid + features: "MESSAGESERVER|ENQUE", + sid: application_sid, + host_id: UUID.uuid4(), + instance_number: "01" ), build( - :database_instance_registered_event, + :application_instance_registered_event, sap_system_id: sap_system_id, - sid: db_sid, + features: "ABAP|GATEWAY|ICMAN|IGS", + sid: application_sid, host_id: deregistered_host_id, - instance_number: deregistered_instance_number, - system_replication: "Primary" + instance_number: deregistered_instance_number + ), + build( + :sap_system_registered_event, + sap_system_id: sap_system_id, + sid: application_sid ), build( - :database_instance_deregistered_event, + :application_instance_deregistered_event, sap_system_id: sap_system_id, host_id: deregistered_host_id, instance_number: deregistered_instance_number, @@ -4458,106 +1918,19 @@ defmodule Trento.SapSystems.SapSystemTest do ) ], [ - %DeregisterDatabaseInstance{ + %DeregisterApplicationInstance{ sap_system_id: sap_system_id, host_id: deregistered_host_id, instance_number: deregistered_instance_number, deregistered_at: DateTime.utc_now() } ], - {:error, :database_instance_not_registered} + {:error, :application_instance_not_registered} ) end end describe "instance marked absent/present" do - test "should mark as absent a previously registered database instance" do - sap_system_id = Faker.UUID.v4() - sid = fake_sid() - host_id = Faker.UUID.v4() - absent_db_instance_number = "01" - present_db_instance_number = "02" - absent_db_absent_at = DateTime.utc_now() - - initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - sid: sid, - host_id: host_id, - instance_number: absent_db_instance_number, - system_replication: nil, - system_replication_status: nil - ), - build( - :database_instance_marked_absent_event, - sap_system_id: sap_system_id, - host_id: host_id, - instance_number: absent_db_instance_number, - absent_at: absent_db_absent_at - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - sid: sid, - host_id: host_id, - instance_number: present_db_instance_number, - system_replication: nil, - system_replication_status: nil - ) - ] - - absent_at = DateTime.utc_now() - - assert_events_and_state( - initial_events, - [ - %MarkDatabaseInstanceAbsent{ - instance_number: absent_db_instance_number, - host_id: host_id, - sap_system_id: sap_system_id, - absent_at: absent_at - }, - %MarkDatabaseInstanceAbsent{ - instance_number: present_db_instance_number, - host_id: host_id, - sap_system_id: sap_system_id, - absent_at: absent_at - } - ], - [ - %DatabaseInstanceMarkedAbsent{ - instance_number: present_db_instance_number, - host_id: host_id, - sap_system_id: sap_system_id, - absent_at: absent_at - } - ], - fn state -> - assert %SapSystem{ - database: %Database{ - sid: ^sid, - instances: [ - %Instance{ - instance_number: ^present_db_instance_number, - absent_at: ^absent_at - }, - %Instance{ - instance_number: ^absent_db_instance_number, - absent_at: ^absent_db_absent_at - } - ] - } - } = state - end - ) - end - test "should mark as absent a previously registered application instance" do sap_system_id = Faker.UUID.v4() sid = fake_sid() @@ -4567,20 +1940,6 @@ defmodule Trento.SapSystems.SapSystemTest do absent_app_absent_at = DateTime.utc_now() initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - sid: sid, - host_id: host_id, - instance_number: "01", - system_replication: nil, - system_replication_status: nil - ), build(:application_instance_registered_event, sap_system_id: sap_system_id, sid: sid, @@ -4588,6 +1947,11 @@ defmodule Trento.SapSystems.SapSystemTest do instance_number: absent_message_server_instance_number, features: "MESSAGESERVER" ), + build( + :sap_system_registered_event, + sap_system_id: sap_system_id, + sid: sid + ), build( :application_instance_marked_absent_event, sap_system_id: sap_system_id, @@ -4632,100 +1996,17 @@ defmodule Trento.SapSystems.SapSystemTest do ], fn state -> assert %SapSystem{ - application: %Application{ - sid: ^sid, - instances: [ - %Instance{ - instance_number: ^present_app_instance_number, - absent_at: ^absent_at - }, - %Instance{ - instance_number: ^absent_message_server_instance_number, - absent_at: ^absent_app_absent_at - } - ] - } - } = state - end - ) - end - - test "should mark as present an already registered, absent database instance" do - sap_system_id = Faker.UUID.v4() - sid = fake_sid() - host_id = Faker.UUID.v4() - absent_db_instance_number = "01" - present_db_instance_number = "02" - - initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - sid: sid, - host_id: host_id, - instance_number: absent_db_instance_number, - system_replication: nil, - system_replication_status: nil - ), - build( - :database_instance_marked_absent_event, - sap_system_id: sap_system_id, - host_id: host_id, - instance_number: absent_db_instance_number, - absent_at: DateTime.utc_now() - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - sid: sid, - host_id: host_id, - instance_number: present_db_instance_number, - system_replication: nil, - system_replication_status: nil - ) - ] - - assert_events_and_state( - initial_events, - [ - %RegisterDatabaseInstance{ - sap_system_id: sap_system_id, - host_id: host_id, - instance_number: absent_db_instance_number, - health: :passing - }, - %RegisterDatabaseInstance{ - sap_system_id: sap_system_id, - host_id: host_id, - instance_number: present_db_instance_number, - health: :passing - } - ], - [ - %DatabaseInstanceMarkedPresent{ - instance_number: absent_db_instance_number, - host_id: host_id, - sap_system_id: sap_system_id - } - ], - fn state -> - assert %SapSystem{ - database: %Database{ - sid: ^sid, - instances: [ - %Instance{ - absent_at: nil - }, - %Instance{ - absent_at: nil - } - ] - } + sid: ^sid, + instances: [ + %Instance{ + instance_number: ^present_app_instance_number, + absent_at: ^absent_at + }, + %Instance{ + instance_number: ^absent_message_server_instance_number, + absent_at: ^absent_app_absent_at + } + ] } = state end ) @@ -4740,20 +2021,6 @@ defmodule Trento.SapSystems.SapSystemTest do present_message_server_instance_number = "03" initial_events = [ - build( - :database_registered_event, - sap_system_id: sap_system_id, - sid: sid - ), - build( - :database_instance_registered_event, - sap_system_id: sap_system_id, - sid: sid, - host_id: host_id, - instance_number: "01", - system_replication: nil, - system_replication_status: nil - ), build(:application_instance_registered_event, sap_system_id: sap_system_id, sid: sid, @@ -4813,17 +2080,14 @@ defmodule Trento.SapSystems.SapSystemTest do assert %SapSystem{ sid: ^sid, ensa_version: ^ensa_version, - application: %Application{ - sid: ^sid, - instances: [ - %Instance{ - absent_at: nil - }, - %Instance{ - absent_at: nil - } - ] - } + instances: [ + %Instance{ + absent_at: nil + }, + %Instance{ + absent_at: nil + } + ] } = state end ) diff --git a/test/trento/sap_systems_test.exs b/test/trento/sap_systems_test.exs index 0388172d79..6b13abc5ed 100644 --- a/test/trento/sap_systems_test.exs +++ b/test/trento/sap_systems_test.exs @@ -12,10 +12,8 @@ defmodule Trento.SapSystemsTest do SapSystemReadModel } - alias Trento.SapSystems.Commands.{ - DeregisterApplicationInstance, - DeregisterDatabaseInstance - } + alias Trento.Databases.Commands.DeregisterDatabaseInstance + alias Trento.SapSystems.Commands.DeregisterApplicationInstance @moduletag :integration @@ -179,7 +177,7 @@ defmodule Trento.SapSystemsTest do Trento.Commanded.Mock, :dispatch, fn %DeregisterDatabaseInstance{ - sap_system_id: ^sap_system_id, + database_id: ^sap_system_id, host_id: ^host_id, instance_number: ^instance_number, deregistered_at: ^deregistered_at diff --git a/test/trento_web/controllers/v1/sap_system_controller_test.exs b/test/trento_web/controllers/v1/sap_system_controller_test.exs index 4629720d28..dd219892dd 100644 --- a/test/trento_web/controllers/v1/sap_system_controller_test.exs +++ b/test/trento_web/controllers/v1/sap_system_controller_test.exs @@ -9,10 +9,8 @@ defmodule TrentoWeb.V1.SapSystemControllerTest do alias TrentoWeb.OpenApi.V1.ApiSpec - alias Trento.SapSystems.Commands.{ - DeregisterApplicationInstance, - DeregisterDatabaseInstance - } + alias Trento.Databases.Commands.DeregisterDatabaseInstance + alias Trento.SapSystems.Commands.DeregisterApplicationInstance setup [:set_mox_from_context, :verify_on_exit!] @@ -145,7 +143,7 @@ defmodule TrentoWeb.V1.SapSystemControllerTest do Trento.Commanded.Mock, :dispatch, fn %DeregisterDatabaseInstance{ - sap_system_id: ^sap_system_id, + database_id: ^sap_system_id, host_id: ^host_id, instance_number: ^instance_number } -> @@ -172,7 +170,7 @@ defmodule TrentoWeb.V1.SapSystemControllerTest do Trento.Commanded.Mock, :dispatch, fn %DeregisterDatabaseInstance{ - sap_system_id: ^sap_system_id, + database_id: ^sap_system_id, host_id: ^host_id, instance_number: ^instance_number } -> @@ -202,7 +200,7 @@ defmodule TrentoWeb.V1.SapSystemControllerTest do Trento.Commanded.Mock, :dispatch, fn %DeregisterDatabaseInstance{ - sap_system_id: ^sap_system_id, + database_id: ^sap_system_id, host_id: ^host_id, instance_number: ^instance_number } ->