From 3602a7688d3b1007cab4f95dba269be9b81e22d7 Mon Sep 17 00:00:00 2001 From: kurilova Date: Mon, 23 Sep 2024 08:19:02 +0000 Subject: [PATCH 1/4] Do not show "Save changes" dialog when there is no changes in profile --- .../risk-assessment.component.spec.ts | 15 +++++- .../risk-assessment.component.ts | 46 ++++++++++++++++++- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.spec.ts b/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.spec.ts index 7b65ca7e6..45dbefd2c 100644 --- a/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.spec.ts +++ b/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.spec.ts @@ -296,7 +296,7 @@ describe('RiskAssessmentComponent', () => { })); it('should call store saveProfile', fakeAsync(() => { - spyOn(component.dialog, 'open').and.returnValue({ + const openSpy = spyOn(component.dialog, 'open').and.returnValue({ afterClosed: () => of(true), } as MatDialogRef); @@ -308,6 +308,19 @@ describe('RiskAssessmentComponent', () => { // @ts-expect-error config is in object expect(args[0].profile).toEqual(NEW_PROFILE_MOCK); expect(mockRiskAssessmentStore.saveProfile).toHaveBeenCalled(); + openSpy.calls.reset(); + })); + + it('should call store saveProfile and should not open save draft profile modal when profile does not have changes', fakeAsync(() => { + const openSpy = spyOn(component.dialog, 'open').and.returnValue({ + afterClosed: () => of(true), + } as MatDialogRef); + + component.saveProfileClicked(PROFILE_MOCK, PROFILE_MOCK); + + expect(openSpy).not.toHaveBeenCalled(); + expect(mockRiskAssessmentStore.saveProfile).toHaveBeenCalled(); + openSpy.calls.reset(); })); it('should close the form', fakeAsync(() => { diff --git a/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.ts b/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.ts index 2abec064e..b235ec8e2 100644 --- a/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.ts +++ b/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.ts @@ -119,7 +119,7 @@ export class RiskAssessmentComponent implements OnInit, OnDestroy { } saveProfileClicked(profile: Profile, selectedProfile: Profile | null): void { - if (!selectedProfile) { + if (!selectedProfile || this.compareProfiles(profile, selectedProfile)) { this.saveProfile(profile, this.store.setFocusOnCreateButton); } else { this.openSaveDialog( @@ -135,6 +135,50 @@ export class RiskAssessmentComponent implements OnInit, OnDestroy { } } + private compareProfiles(profile1: Profile, profile2: Profile) { + if (profile1.name !== profile2.name) { + return false; + } + if ( + profile1.rename === profile1.name && + profile1.rename !== profile2.name + ) { + return false; + } + if (profile1.status !== profile2.status) { + return false; + } + + for (const question of profile1.questions) { + const answer1 = question.answer; + const answer2 = profile2.questions?.find( + question2 => question2.question === question.question + )?.answer; + if (answer1 !== undefined && answer2 !== undefined) { + if (typeof question.answer === 'string') { + if (answer1 !== answer2) { + return false; + } + } else { + //the type of answer is array + if (answer1?.length !== answer2?.length) { + return false; + } + if ( + (answer1 as number[]).some( + answer => !(answer2 as number[]).includes(answer) + ) + ) + return false; + } + } else { + return !!answer1 == !!answer2; + } + } + + return true; + } + discard(selectedProfile: Profile | null) { this.isOpenProfileForm = false; if (selectedProfile) { From 93a1e12d5f823bd429106aa2611c535835869884 Mon Sep 17 00:00:00 2001 From: kurilova Date: Mon, 23 Sep 2024 09:29:09 +0000 Subject: [PATCH 2/4] Clear announce message on form close --- .../src/app/pages/risk-assessment/risk-assessment.component.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.ts b/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.ts index b235ec8e2..363e06af1 100644 --- a/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.ts +++ b/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.ts @@ -119,6 +119,7 @@ export class RiskAssessmentComponent implements OnInit, OnDestroy { } saveProfileClicked(profile: Profile, selectedProfile: Profile | null): void { + this.liveAnnouncer.clear(); if (!selectedProfile || this.compareProfiles(profile, selectedProfile)) { this.saveProfile(profile, this.store.setFocusOnCreateButton); } else { @@ -180,6 +181,7 @@ export class RiskAssessmentComponent implements OnInit, OnDestroy { } discard(selectedProfile: Profile | null) { + this.liveAnnouncer.clear(); this.isOpenProfileForm = false; if (selectedProfile) { this.store.setFocusOnSelectedProfile(); From 714a578b3ec627ba01ad70c0397a1eaec25bdd3b Mon Sep 17 00:00:00 2001 From: jhughesbiot Date: Mon, 23 Sep 2024 02:04:05 -0600 Subject: [PATCH 3/4] Add mac address filter for the device interface to single ip test (#791) * Add mac address filter for the device interface to single ip test * pylint --------- Co-authored-by: J Boddey --- framework/python/src/common/session.py | 4 ++++ framework/python/src/core/docker/test_docker_module.py | 1 + framework/python/src/net_orc/ip_control.py | 10 ++++++++++ modules/test/base/python/src/test_module.py | 1 + modules/test/conn/python/src/connection_module.py | 3 ++- 5 files changed, 18 insertions(+), 1 deletion(-) diff --git a/framework/python/src/common/session.py b/framework/python/src/common/session.py index b617ddf15..5c53e21c5 100644 --- a/framework/python/src/common/session.py +++ b/framework/python/src/common/session.py @@ -282,6 +282,10 @@ def add_runtime_param(self, param): def get_device_interface(self): return self._config.get(NETWORK_KEY, {}).get(DEVICE_INTF_KEY) + def get_device_interface_mac_addr(self): + iface = self.get_device_interface() + return IPControl.get_iface_mac_address(iface=iface) + def get_internet_interface(self): return self._config.get(NETWORK_KEY, {}).get(INTERNET_INTF_KEY) diff --git a/framework/python/src/core/docker/test_docker_module.py b/framework/python/src/core/docker/test_docker_module.py index b8315e15d..4bbf72594 100644 --- a/framework/python/src/core/docker/test_docker_module.py +++ b/framework/python/src/core/docker/test_docker_module.py @@ -102,6 +102,7 @@ def get_environment(self, device): 'IPV4_SUBNET': self.get_session().get_ipv4_subnet(), 'IPV6_SUBNET': self.get_session().get_ipv6_subnet(), 'DEV_IFACE': self.get_session().get_device_interface(), + 'DEV_IFACE_MAC': self.get_session().get_device_interface_mac_addr() } return environment diff --git a/framework/python/src/net_orc/ip_control.py b/framework/python/src/net_orc/ip_control.py index 544b1537b..aa07283af 100644 --- a/framework/python/src/net_orc/ip_control.py +++ b/framework/python/src/net_orc/ip_control.py @@ -89,6 +89,16 @@ def get_iface_connection_stats(self, iface): else: return None + @staticmethod + def get_iface_mac_address(iface): + net_if_addrs = psutil.net_if_addrs() + if iface in net_if_addrs: + for addr_info in net_if_addrs[iface]: + # AF_LINK corresponds to the MAC address + if addr_info.family == psutil.AF_LINK: + return addr_info.address + return None + def get_iface_port_stats(self, iface): """Extract information about packets connection""" response = util.run_command(f'ethtool -S {iface}') diff --git a/modules/test/base/python/src/test_module.py b/modules/test/base/python/src/test_module.py index ee0fab1c5..1487fb786 100644 --- a/modules/test/base/python/src/test_module.py +++ b/modules/test/base/python/src/test_module.py @@ -41,6 +41,7 @@ def __init__(self, self._ipv4_addr = os.environ.get('IPV4_ADDR', '') self._ipv4_subnet = os.environ.get('IPV4_SUBNET', '') self._ipv6_subnet = os.environ.get('IPV6_SUBNET', '') + self._dev_iface_mac = os.environ.get('DEV_IFACE_MAC', '') self._add_logger(log_name=log_name, module_name=module_name, log_dir=log_dir) diff --git a/modules/test/conn/python/src/connection_module.py b/modules/test/conn/python/src/connection_module.py index 488627833..867d8a3ff 100644 --- a/modules/test/conn/python/src/connection_module.py +++ b/modules/test/conn/python/src/connection_module.py @@ -246,7 +246,8 @@ def _connection_single_ip(self): if self._get_dhcp_type(packet) == 3: mac_address = packet[Ether].src LOGGER.info('DHCPREQUEST detected MAC address: ' + mac_address) - if not mac_address.startswith(TR_CONTAINER_MAC_PREFIX): + if (not mac_address.startswith(TR_CONTAINER_MAC_PREFIX) + and mac_address != self._dev_iface_mac): mac_addresses.add(mac_address.upper()) # Check if the device mac address is in the list of DHCPREQUESTs From 46eeee027244661e8ecea00a9ac53935e40fdf0b Mon Sep 17 00:00:00 2001 From: kurilova Date: Mon, 23 Sep 2024 09:41:07 +0000 Subject: [PATCH 4/4] Clear announce message on form close --- .../app/pages/risk-assessment/risk-assessment.component.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.spec.ts b/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.spec.ts index 45dbefd2c..095f8c774 100644 --- a/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.spec.ts +++ b/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.spec.ts @@ -48,6 +48,7 @@ describe('RiskAssessmentComponent', () => { const mockLiveAnnouncer: SpyObj = jasmine.createSpyObj([ 'announce', + 'clear', ]); let compiled: HTMLElement;