diff --git a/assets/js/lib/test-utils/factories/sapSystems.js b/assets/js/lib/test-utils/factories/sapSystems.js
index 55e60c6f51..6d50f42f82 100644
--- a/assets/js/lib/test-utils/factories/sapSystems.js
+++ b/assets/js/lib/test-utils/factories/sapSystems.js
@@ -15,6 +15,7 @@ const roles = () =>
'GATEWAY',
'ICMAN',
'IGS',
+ 'J2EE',
]);
export const sapSystemApplicationInstanceFactory = Factory.define(() => ({
diff --git a/assets/js/pages/SapSystemsOverviewPage/SapSystemsOverview.jsx b/assets/js/pages/SapSystemsOverviewPage/SapSystemsOverview.jsx
index d00c0d00f7..4243fa2b71 100644
--- a/assets/js/pages/SapSystemsOverviewPage/SapSystemsOverview.jsx
+++ b/assets/js/pages/SapSystemsOverviewPage/SapSystemsOverview.jsx
@@ -1,7 +1,7 @@
/* eslint-disable react/no-unstable-nested-components */
import React, { useState } from 'react';
import { Link, useSearchParams } from 'react-router-dom';
-import { filter } from 'lodash';
+import { filter, uniq, flatMap } from 'lodash';
import { getEnsaVersionLabel } from '@lib/model/sapSystems';
@@ -77,6 +77,17 @@ function SapSystemsOverview({
title: 'Tenant',
key: 'tenant',
},
+ {
+ title: 'Type',
+ key: 'applicationInstances',
+ render: (content) =>
+ uniq(flatMap(content, ({ features }) => features.split('|')))
+ .filter((item) => item === 'J2EE' || item === 'ABAP')
+ .map((item) => (item === 'J2EE' ? 'JAVA' : item))
+ .toSorted()
+ .join('/'),
+ },
+
{
title: 'DB Address',
key: 'dbAddress',
diff --git a/assets/js/pages/SapSystemsOverviewPage/SapSystemsOverview.stories.jsx b/assets/js/pages/SapSystemsOverviewPage/SapSystemsOverview.stories.jsx
index 4b5431d3a1..6646a864b6 100644
--- a/assets/js/pages/SapSystemsOverviewPage/SapSystemsOverview.stories.jsx
+++ b/assets/js/pages/SapSystemsOverviewPage/SapSystemsOverview.stories.jsx
@@ -5,6 +5,7 @@ import { MemoryRouter } from 'react-router-dom';
import {
clusterFactory,
hostFactory,
+ sapSystemApplicationInstanceFactory,
sapSystemFactory,
} from '@lib/test-utils/factories';
@@ -19,6 +20,7 @@ const enrichInstances = (systems, instanceType) =>
const cluster = clusterFactory.build();
return {
...instance,
+ features: 'ABAP',
host: {
...hostFactory.build({
id: instance.host_id,
@@ -49,6 +51,28 @@ const enrichedAbsentDatabaseInstances = enrichInstances(
'database_instances'
);
+const sapSystemTypes = [
+ 'ABAP',
+ 'J2EE',
+ 'ABAP|J2EE',
+ 'J2EE|ABAP',
+ 'SOME_SAP_SYSTEM_FEATURE|NOT_A_REAL_SYSTEM',
+];
+
+const sapSystemsWithCustomTypes = sapSystemTypes.map((type) => {
+ const sapSystemID = faker.string.uuid();
+ return sapSystemFactory.build({
+ id: sapSystemID,
+ application_instances: sapSystemApplicationInstanceFactory.buildList(2, {
+ sap_system_id: sapSystemID,
+ features: type,
+ }),
+ });
+});
+const sapSystemApplicationInstances = sapSystemsWithCustomTypes
+ .map((sapSystem) => sapSystem.application_instances)
+ .flat();
+
enrichedAbsentApplicationInstances[1].absent_at = faker.date
.past()
.toISOString();
@@ -71,10 +95,6 @@ export default {
control: { type: 'array' },
description: 'Application instances',
},
- userAbilities: {
- control: { type: 'array' },
- description: 'User profile abilities',
- },
databaseInstances: {
control: { type: 'array' },
description: 'Database instances',
@@ -87,6 +107,10 @@ export default {
defaultValue: { summary: false },
},
},
+ userAbilities: {
+ control: { type: 'array' },
+ description: 'User profile abilities',
+ },
onTagAdd: {
action: 'Add tag',
description: 'Called when a new tag is added',
@@ -140,3 +164,11 @@ export const UnauthorizedCleanUp = {
userAbilities: [],
},
};
+export const SapSystemsWithDifferentTypes = {
+ args: {
+ userAbilities,
+ sapSystems: sapSystemsWithCustomTypes,
+ applicationInstances: sapSystemApplicationInstances,
+ databaseInstances: {},
+ },
+};
diff --git a/assets/js/pages/SapSystemsOverviewPage/SapSystemsOverview.test.jsx b/assets/js/pages/SapSystemsOverviewPage/SapSystemsOverview.test.jsx
index edd759c2ec..81d796abc7 100644
--- a/assets/js/pages/SapSystemsOverviewPage/SapSystemsOverview.test.jsx
+++ b/assets/js/pages/SapSystemsOverviewPage/SapSystemsOverview.test.jsx
@@ -8,6 +8,7 @@ import userEvent from '@testing-library/user-event';
import {
clusterFactory,
hostFactory,
+ sapSystemApplicationInstanceFactory,
sapSystemFactory,
} from '@lib/test-utils/factories';
import { renderWithRouter } from '@lib/test-utils';
@@ -41,16 +42,25 @@ describe('SapSystemsOverviews component', () => {
});
it('should display the correct content for a SAP system main row', () => {
- const sapSystem = sapSystemFactory.build({ ensa_version: 'ensa1' });
- const {
+ const sapSystemType = 'ABAP';
+ const sapSystemID = faker.string.uuid();
+
+ const sapSystem = sapSystemFactory.build({
id: sapSystemID,
- sid,
+ ensa_version: 'ensa1',
+ application_instances: sapSystemApplicationInstanceFactory.buildList(
+ 2,
+ { sap_system_id: sapSystemID, features: sapSystemType }
+ ),
+ });
+ const {
tenant,
db_host: dbAddress,
application_instances: applicationInstances,
database_instances: databaseInstances,
database_id: databaseID,
database_sid: attachedRdbms,
+ sid,
} = sapSystem;
renderWithRouter(
@@ -80,13 +90,95 @@ describe('SapSystemsOverviews component', () => {
tenant
);
expect(mainRow.querySelector('td:nth-child(5)')).toHaveTextContent(
- dbAddress
+ sapSystemType
);
expect(mainRow.querySelector('td:nth-child(6)')).toHaveTextContent(
+ dbAddress
+ );
+ expect(mainRow.querySelector('td:nth-child(7)')).toHaveTextContent(
'ENSA1'
);
});
+ it('should display the correct SAP system type JAVA or ABAP', () => {
+ const sapSystemTypes = [
+ 'ABAP',
+ 'J2EE',
+ 'SOME_SAP_SYSTEM_FEATURE|NOT_A_REAL_SYSTEM',
+ ];
+
+ const expectedSapSystemTypes = ['ABAP', 'JAVA', ''];
+
+ const sapSystems = sapSystemTypes.map((type) => {
+ const sapSystemID = faker.string.uuid();
+ return sapSystemFactory.build({
+ id: sapSystemID,
+ application_instances: sapSystemApplicationInstanceFactory.buildList(
+ 2,
+ { sap_system_id: sapSystemID, features: type }
+ ),
+ });
+ });
+
+ const sapSystemApplicationInstances = sapSystems
+ .map((sapSystem) => sapSystem.application_instances)
+ .flat();
+
+ renderWithRouter(
+
+ );
+ const rows = screen.getByRole('table').querySelectorAll('tbody > tr');
+ expectedSapSystemTypes.forEach((expectedType, index) => {
+ const rowIndex = index * 2;
+ const sapSystemRow = rows[rowIndex];
+ expect(sapSystemRow.querySelector('td:nth-child(5)')).toHaveTextContent(
+ expectedType
+ );
+ });
+ });
+
+ it('should display the correct SAP system type JAVA and ABAP', () => {
+ const expectedSapSystemTypes = 'ABAP/JAVA';
+ const sapSystemID = faker.string.uuid();
+ const sapSystem = sapSystemFactory.build({
+ id: sapSystemID,
+ application_instances: [
+ sapSystemApplicationInstanceFactory.build({
+ sap_system_id: sapSystemID,
+ features: 'ABAP',
+ }),
+ sapSystemApplicationInstanceFactory.build({
+ sap_system_id: sapSystemID,
+ features: 'J2EE',
+ }),
+ sapSystemApplicationInstanceFactory.build({
+ sap_system_id: sapSystemID,
+ features: 'SOME_SAP_SYSTEM_FEATURE|OTHER_SAP_APP',
+ }),
+ ],
+ });
+
+ const { application_instances: applicationInstances } = sapSystem;
+
+ renderWithRouter(
+
+ );
+ const rows = screen.getByRole('table').querySelectorAll('tbody > tr');
+ expect(rows[0].querySelector('td:nth-child(5)')).toHaveTextContent(
+ expectedSapSystemTypes
+ );
+ });
+
it('should display the correct content for a SAP system instances', () => {
const sapSystem = sapSystemFactory.build();
const {
diff --git a/lib/trento/sap_systems/sap_system.ex b/lib/trento/sap_systems/sap_system.ex
index ce8d37489d..70a0edc720 100644
--- a/lib/trento/sap_systems/sap_system.ex
+++ b/lib/trento/sap_systems/sap_system.ex
@@ -638,7 +638,7 @@ defmodule Trento.SapSystems.SapSystem do
database_health: database_health
}
) do
- if instances_have_abap?(instances) and instances_have_messageserver?(instances) do
+ if instances_have_abap_or_java?(instances) and instances_have_messageserver?(instances) do
%SapSystemRestored{
db_host: db_host,
health: health,
@@ -659,7 +659,7 @@ defmodule Trento.SapSystems.SapSystem do
database_health: database_health
}
) do
- if instances_have_abap?(instances) and instances_have_messageserver?(instances) do
+ if instances_have_abap_or_java?(instances) and instances_have_messageserver?(instances) do
%SapSystemRestored{
health: health,
db_host: db_host,
@@ -683,7 +683,7 @@ defmodule Trento.SapSystems.SapSystem do
database_health: database_health
}
) do
- if instances_have_abap?(instances) and instances_have_messageserver?(instances) do
+ if instances_have_abap_or_java?(instances) and instances_have_messageserver?(instances) do
%SapSystemRegistered{
sap_system_id: sap_system_id,
sid: sid,
@@ -794,7 +794,7 @@ defmodule Trento.SapSystems.SapSystem do
},
deregistered_at
) do
- unless instances_have_abap?(instances) and instances_have_messageserver?(instances) do
+ unless instances_have_abap_or_java?(instances) and instances_have_messageserver?(instances) do
%SapSystemDeregistered{sap_system_id: sap_system_id, deregistered_at: deregistered_at}
end
end
@@ -814,6 +814,14 @@ defmodule Trento.SapSystems.SapSystem do
Enum.any?(instances, fn %{features: features} -> features =~ "ABAP" end)
end
+ defp instances_have_java?(instances) do
+ Enum.any?(instances, fn %{features: features} -> features =~ "J2EE" end)
+ end
+
+ defp instances_have_abap_or_java?(instances) do
+ instances_have_abap?(instances) or instances_have_java?(instances)
+ end
+
def instances_have_messageserver?(instances) do
Enum.any?(instances, fn %{features: features} -> features =~ "MESSAGESERVER" 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 d072d60ef3..116707ee36 100644
--- a/test/e2e/cypress/e2e/sap_systems_overview.cy.js
+++ b/test/e2e/cypress/e2e/sap_systems_overview.cy.js
@@ -73,7 +73,8 @@ context('SAP Systems Overview', () => {
.within(() => {
cy.get('td').eq(2).contains(attachedDatabase.sid);
cy.get('td').eq(3).contains(attachedDatabase.tenant);
- cy.get('td').eq(4).contains(attachedDatabase.dbAddress);
+
+ cy.get('td').eq(5).contains(attachedDatabase.dbAddress);
});
});
it(`should have a link to the attached HANA database with id: ${attachedDatabase.id}`, () => {
diff --git a/test/trento/sap_systems/sap_system_test.exs b/test/trento/sap_systems/sap_system_test.exs
index a19037b715..0b6459f9c6 100644
--- a/test/trento/sap_systems/sap_system_test.exs
+++ b/test/trento/sap_systems/sap_system_test.exs
@@ -124,6 +124,92 @@ defmodule Trento.SapSystems.SapSystemTest do
)
end
+ test "should register a SAP System and add an application instance when a MESSAGESERVER instance is already present and a new JAVA instance is added" do
+ sap_system_id = Faker.UUID.v4()
+ sid = Faker.StarWars.planet()
+ db_host = Faker.Internet.ip_v4_address()
+ tenant = Faker.Beer.style()
+ instance_hostname = Faker.Airports.iata()
+ http_port = 80
+ https_port = 443
+ start_priority = "0.9"
+ host_id = Faker.UUID.v4()
+ ensa_version = EnsaVersion.ensa1()
+ java_system_type = "J2EE"
+
+ initial_events = [
+ build(:application_instance_registered_event,
+ sap_system_id: sap_system_id,
+ sid: sid,
+ features: "MESSAGESERVER",
+ instance_number: "00"
+ )
+ ]
+
+ assert_events_and_state(
+ initial_events,
+ RegisterApplicationInstance.new!(%{
+ sap_system_id: sap_system_id,
+ sid: sid,
+ db_host: db_host,
+ tenant: tenant,
+ instance_number: "10",
+ instance_hostname: instance_hostname,
+ features: java_system_type,
+ http_port: http_port,
+ https_port: https_port,
+ start_priority: start_priority,
+ host_id: host_id,
+ health: :passing,
+ ensa_version: ensa_version,
+ database_health: :passing
+ }),
+ [
+ %ApplicationInstanceRegistered{
+ sap_system_id: sap_system_id,
+ sid: sid,
+ instance_number: "10",
+ instance_hostname: instance_hostname,
+ features: java_system_type,
+ http_port: http_port,
+ https_port: https_port,
+ start_priority: start_priority,
+ host_id: host_id,
+ health: :passing
+ },
+ %SapSystemRegistered{
+ sap_system_id: sap_system_id,
+ sid: sid,
+ db_host: db_host,
+ tenant: tenant,
+ health: :passing,
+ database_health: :passing,
+ ensa_version: ensa_version
+ }
+ ],
+ fn state ->
+ assert %SapSystem{
+ sid: ^sid,
+ ensa_version: ^ensa_version,
+ database_health: :passing,
+ instances: [
+ %Instance{
+ sid: ^sid,
+ instance_number: "10",
+ features: ^java_system_type,
+ host_id: ^host_id,
+ health: :passing,
+ absent_at: nil
+ },
+ %Instance{
+ features: "MESSAGESERVER"
+ }
+ ]
+ } = state
+ end
+ )
+ end
+
test "should move an application instance if the host_id changed and the instance number already exists and the application is clustered" do
sap_system_id = Faker.UUID.v4()
sid = fake_sid()
@@ -1243,16 +1329,21 @@ defmodule Trento.SapSystems.SapSystemTest do
end
describe "tombstoning" do
- test "should tombstone a deregistered SAP system when no application instances are left" do
+ test "should tombstone a deregistered SAP system when no ABAP or JAVA application instances are left" do
sap_system_id = UUID.uuid4()
deregistered_at = DateTime.utc_now()
message_server_host_id = UUID.uuid4()
message_server_instance_number = "00"
abap_host_id = UUID.uuid4()
+ java_host_id = UUID.uuid4()
abap_instance_number = "01"
+ java_instance_number = "02"
application_sid = fake_sid()
+ # Sap System type
+ abap_system_type = "ABAP"
+ java_system_type = "J2EE"
initial_events = [
build(
@@ -1266,11 +1357,19 @@ defmodule Trento.SapSystems.SapSystemTest do
build(
:application_instance_registered_event,
sap_system_id: sap_system_id,
- features: "ABAP|GATEWAY|ICMAN|IGS",
+ features: abap_system_type,
host_id: abap_host_id,
sid: application_sid,
instance_number: abap_instance_number
),
+ build(
+ :application_instance_registered_event,
+ sap_system_id: sap_system_id,
+ features: java_system_type,
+ host_id: java_host_id,
+ sid: application_sid,
+ instance_number: java_instance_number
+ ),
build(
:sap_system_registered_event,
sap_system_id: sap_system_id,
@@ -1292,6 +1391,12 @@ defmodule Trento.SapSystems.SapSystemTest do
host_id: abap_host_id,
instance_number: abap_instance_number,
deregistered_at: deregistered_at
+ },
+ %DeregisterApplicationInstance{
+ sap_system_id: sap_system_id,
+ host_id: java_host_id,
+ instance_number: java_instance_number,
+ deregistered_at: deregistered_at
}
],
[
@@ -1311,6 +1416,12 @@ defmodule Trento.SapSystems.SapSystemTest do
instance_number: abap_instance_number,
deregistered_at: deregistered_at
},
+ %ApplicationInstanceDeregistered{
+ sap_system_id: sap_system_id,
+ host_id: java_host_id,
+ instance_number: java_instance_number,
+ deregistered_at: deregistered_at
+ },
%SapSystemTombstoned{
sap_system_id: sap_system_id
}