You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@metron.apache.org by sa...@apache.org on 2019/12/03 15:58:23 UTC
[metron] branch master updated: METRON-2323 Increase unit test
coverage for Alerts List (sardell) closes apache/metron#1567
This is an automated email from the ASF dual-hosted git repository.
sardell pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/metron.git
The following commit(s) were added to refs/heads/master by this push:
new 9b4979d METRON-2323 Increase unit test coverage for Alerts List (sardell) closes apache/metron#1567
9b4979d is described below
commit 9b4979d69319436af5a65fd52bc555f794aa5029
Author: sardell <sh...@gmail.com>
AuthorDate: Tue Dec 3 10:57:35 2019 -0500
METRON-2323 Increase unit test coverage for Alerts List (sardell) closes apache/metron#1567
---
.../alerts/alerts-list/alerts-list.component.html | 12 +-
.../alerts-list/alerts-list.component.spec.ts | 184 ++++++++++++++++++++-
.../alerts/alerts-list/alerts-list.component.ts | 16 --
3 files changed, 188 insertions(+), 24 deletions(-)
diff --git a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.html b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.html
index ea09288..a078e8f 100755
--- a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.html
+++ b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.html
@@ -76,13 +76,13 @@
<app-auto-polling #autoPolling></app-auto-polling>
<div id="table-actions" class="dropdown d-inline-block">
- <button class="btn btn-primary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">ACTIONS</button>
+ <button class="btn btn-primary dropdown-toggle" type="button" id="dropdownMenuButton" data-qe-id="dropdown-menu-button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">ACTIONS</button>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenuButton">
- <span class="dropdown-item" [class.disabled]="selectedAlerts.length == 0" (click)="processOpen($event)">Open</span>
- <span class="dropdown-item" [class.disabled]="selectedAlerts.length == 0" (click)="processDismiss($event)">Dismiss</span>
- <span class="dropdown-item" [class.disabled]="selectedAlerts.length == 0" (click)="processEscalate($event)">Escalate</span>
- <span class="dropdown-item" [class.disabled]="selectedAlerts.length == 0" (click)="processResolve($event)">Resolve</span>
- <span class="dropdown-item" [class.disabled]="selectedAlerts.length == 0 || isMetaAlertPresentInSelectedAlerts" (click)="processAddToAlert($event)">Add to Alert</span>
+ <span class="dropdown-item" data-qe-id="action-open-button" [class.disabled]="selectedAlerts.length == 0" (click)="processOpen($event)">Open</span>
+ <span class="dropdown-item" data-qe-id="action-dismiss-button" [class.disabled]="selectedAlerts.length == 0" (click)="processDismiss($event)">Dismiss</span>
+ <span class="dropdown-item" data-qe-id="action-escalate-button" [class.disabled]="selectedAlerts.length == 0" (click)="processEscalate($event)">Escalate</span>
+ <span class="dropdown-item" data-qe-id="action-resolve-button" [class.disabled]="selectedAlerts.length == 0" (click)="processResolve($event)">Resolve</span>
+ <span class="dropdown-item" data-qe-id="action-add-to-alert-button" [class.disabled]="selectedAlerts.length == 0 || isMetaAlertPresentInSelectedAlerts" (click)="processAddToAlert($event)">Add to Alert</span>
</div>
</div>
</div>
diff --git a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.spec.ts b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.spec.ts
index 74d0f8c..7238555 100644
--- a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.spec.ts
+++ b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.spec.ts
@@ -35,13 +35,15 @@ import { Filter } from 'app/model/filter';
import { QueryBuilder, FilteringMode } from './query-builder';
import { SearchResponse } from 'app/model/search-response';
import { AutoPollingService } from './auto-polling/auto-polling.service';
-import { Router } from '@angular/router';
+import { Router, NavigationStart } from '@angular/router';
import { Alert } from 'app/model/alert';
import { AlertSource } from 'app/model/alert-source';
import { SearchRequest } from 'app/model/search-request';
import { query } from '@angular/core/src/render3';
import { RestError } from 'app/model/rest-error';
import { DialogType } from 'app/shared/metron-dialog/metron-dialog.component';
+import { DateFilterValue } from 'app/model/date-filter-value';
+import { SaveSearch } from 'app/model/save-search';
@Component({
selector: 'app-auto-polling',
@@ -160,10 +162,12 @@ describe('AlertsListComponent', () => {
} } },
{ provide: UpdateService, useClass: () => { return {
alertChanged$: new Observable(),
+ updateAlertState: () => of(),
} } },
{ provide: ConfigureTableService, useClass: () => { return {
getTableMetadata: () => new Observable(),
tableChanged$: new Observable(),
+ saveTableMetaData: () => of(),
} } },
{ provide: AlertsService, useClass: () => { return {} } },
{ provide: ClusterMetaDataService, useClass: () => { return {
@@ -172,9 +176,14 @@ describe('AlertsListComponent', () => {
{ provide: SaveSearchService, useClass: () => { return {
loadSavedSearch$: new Observable(),
setCurrentQueryBuilderAndTableColumns: () => {},
+ fireLoadSavedSearch: (savedSearch: any) => {
+ this.loadSavedSearch$.next(savedSearch);
+ },
+ saveAsRecentSearches: (savedSearch: any) => of(),
} } },
{ provide: MetaAlertService, useClass: () => { return {
alertChanged$: new Observable(),
+ selectedAlerts: []
} } },
{ provide: GlobalConfigService, useClass: () => { return {
get: () => new Observable(),
@@ -183,7 +192,7 @@ describe('AlertsListComponent', () => {
{ provide: QueryBuilder, useClass: () => { return {
filters: [],
query: '*',
- get searchRequest() {
+ searchRequest: () => {
return new SearchResponse();
},
addOrUpdateFilter: () => {},
@@ -193,6 +202,7 @@ describe('AlertsListComponent', () => {
setManualQuery: () => {},
getFilteringMode: () => {},
setFilteringMode: () => {},
+ setSearch: () => {},
} } },
{ provide: AutoPollingService, useClass: () => { return {
data: new Subject<SearchResponse>(),
@@ -202,6 +212,7 @@ describe('AlertsListComponent', () => {
dropNextAndContinue: () => {},
onDestroy: () => {},
setSuppression: () => {},
+ setInterval: () => {},
} } },
]
})
@@ -221,6 +232,28 @@ describe('AlertsListComponent', () => {
expect(component).toBeTruthy();
});
+ it('should get global config on init', () => {
+ const globalConfig = { 'source.type.field': 'test'}
+ const globalConfigService = TestBed.get(GlobalConfigService);
+ spyOn(globalConfigService, 'get').and.returnValue(of(globalConfig));
+ component.ngOnInit();
+ component.alertsColumns = [
+ { name: 'ip:source', type: 'testType' },
+ { name: 'source:type', type: 'testType' }
+ ];
+ fixture.detectChanges();
+ expect(component.globalConfig).toEqual(globalConfig);
+ expect(component.alertsColumns.length).toEqual(2);
+ });
+
+ it('should clear selected alerts if NavigationStart', () => {
+ const router = TestBed.get(Router);
+ spyOn(router, 'events').and.returnValue({url: '/alerts-list'} instanceof NavigationStart);
+ component.ngOnInit();
+ fixture.detectChanges();
+ expect(component.selectedAlerts).toEqual([]);
+ });
+
it('should set default query time range', () => {
expect(component.selectedTimeRange instanceof Filter).toBeTruthy();
expect(component.selectedTimeRange.value).toBe('last-15-minutes');
@@ -589,6 +622,17 @@ describe('AlertsListComponent', () => {
});
describe('search', () => {
+ it('should fire onSearch if in manual search mode', () => {
+ const testQuery = 'test';
+ spyOn(queryBuilder, 'setFilteringMode').and.returnValue(FilteringMode.BUILDER);
+ spyOn(queryBuilder, 'setSearch');
+ spyOn(component, 'search');
+ component.toggleQueryBuilderMode();
+ fixture.detectChanges();
+ component.onSearch(testQuery);
+ expect(queryBuilder.setSearch).toHaveBeenCalledWith(testQuery);
+ });
+
it('should show notification on http error', fakeAsync(() => {
const fakeDialogService = TestBed.get(DialogService);
@@ -600,5 +644,141 @@ describe('AlertsListComponent', () => {
expect(fakeDialogService.launchDialog).toHaveBeenCalledWith('Server were unable to apply query string.', DialogType.Error);
}));
+
+ it('should save current search', () => {
+ const saveSearchService = TestBed.get(SaveSearchService);
+ const search = new SaveSearch();
+
+ spyOn(saveSearchService, 'saveAsRecentSearches').and.callThrough();
+ spyOn(queryBuilder, 'query').and.returnValue('test');
+ component.saveCurrentSearch(search);
+ expect(saveSearchService.saveAsRecentSearches).toHaveBeenCalledWith(search);
+ });
+ });
+
+ describe('actions', () => {
+ const testAlert: Alert = {
+ id: '123',
+ score: 123,
+ source: new AlertSource(),
+ status: 'TEST',
+ index: 'test'
+ }
+
+ it('should prevent a user from selecting a new alert state if disabled', () => {
+ const updateService = TestBed.get(UpdateService);
+ spyOn(updateService, 'updateAlertState')
+ spyOn(component, 'preventDropdownOptionIfDisabled');
+ const actionsButton = fixture.debugElement.nativeElement.querySelector('[data-qe-id="dropdown-menu-button"');
+ actionsButton.click();
+ const openButton = fixture.debugElement.nativeElement.querySelector('[data-qe-id="action-open-button"');
+ expect(openButton.classList).toContain('disabled');
+ openButton.dispatchEvent(new Event('click'));
+ expect(component.preventDropdownOptionIfDisabled).toHaveBeenCalled();
+ expect(updateService.updateAlertState).not.toHaveBeenCalled();
+ });
+
+
+ it('should update the alert state to open when selected', () => {
+ component.selectedAlerts.push(testAlert);
+ fixture.detectChanges();
+ const updateService = TestBed.get(UpdateService);
+ spyOn(updateService, 'updateAlertState').and.returnValue(of({}));
+ spyOn(component, 'processOpen').and.callThrough();
+ spyOn(component, 'updateSelectedAlertStatus');
+ const actionsButton = fixture.debugElement.nativeElement.querySelector('[data-qe-id="dropdown-menu-button"');
+ actionsButton.click();
+ const openButton = fixture.debugElement.nativeElement.querySelector('[data-qe-id="action-open-button"');
+ openButton.dispatchEvent(new Event('click'));
+ fixture.detectChanges();
+ expect(component.processOpen).toHaveBeenCalled();
+ expect(updateService.updateAlertState).toHaveBeenCalledWith(component.selectedAlerts, 'OPEN', false);
+ });
+
+ it('should update the alert state to dismiss when selected', () => {
+ component.selectedAlerts.push(testAlert);
+ fixture.detectChanges();
+ const updateService = TestBed.get(UpdateService);
+ spyOn(updateService, 'updateAlertState').and.returnValue(of());
+ spyOn(component, 'processDismiss').and.callThrough();
+ spyOn(component, 'updateSelectedAlertStatus');
+ const actionsButton = fixture.debugElement.nativeElement.querySelector('[data-qe-id="dropdown-menu-button"');
+ actionsButton.click();
+ const dismissButton = fixture.debugElement.nativeElement.querySelector('[data-qe-id="action-dismiss-button"');
+ dismissButton.dispatchEvent(new Event('click'));
+ fixture.detectChanges();
+ expect(component.processDismiss).toHaveBeenCalled();
+ expect(updateService.updateAlertState).toHaveBeenCalledWith(component.selectedAlerts, 'DISMISS', false);
+ });
+
+ it('should update the alert state to escalate when selected', () => {
+ component.selectedAlerts.push(testAlert);
+ fixture.detectChanges();
+ const updateService = TestBed.get(UpdateService);
+ spyOn(updateService, 'updateAlertState').and.returnValue(of());
+ spyOn(component, 'processEscalate').and.callThrough();
+ spyOn(component, 'updateSelectedAlertStatus');
+ const actionsButton = fixture.debugElement.nativeElement.querySelector('[data-qe-id="dropdown-menu-button"');
+ actionsButton.click();
+ const escalateButton = fixture.debugElement.nativeElement.querySelector('[data-qe-id="action-escalate-button"');
+ escalateButton.dispatchEvent(new Event('click'));
+ fixture.detectChanges();
+ expect(component.processEscalate).toHaveBeenCalled();
+ expect(updateService.updateAlertState).toHaveBeenCalledWith(component.selectedAlerts, 'ESCALATE', false);
+ });
+
+ it('should update the alert state to resolve when selected', () => {
+ component.selectedAlerts.push(testAlert);
+ fixture.detectChanges();
+ const updateService = TestBed.get(UpdateService);
+ spyOn(updateService, 'updateAlertState').and.returnValue(of());
+ spyOn(component, 'processResolve').and.callThrough();
+ spyOn(component, 'updateSelectedAlertStatus');
+ const actionsButton = fixture.debugElement.nativeElement.querySelector('[data-qe-id="dropdown-menu-button"');
+ actionsButton.click();
+ const resolveButton = fixture.debugElement.nativeElement.querySelector('[data-qe-id="action-resolve-button"');
+ resolveButton.dispatchEvent(new Event('click'));
+ fixture.detectChanges();
+ expect(component.processResolve).toHaveBeenCalled();
+ expect(updateService.updateAlertState).toHaveBeenCalledWith(component.selectedAlerts, 'RESOLVE', false);
+ });
+
+ it('should add to alert when selected', () => {
+ component.selectedAlerts.push(testAlert);
+ fixture.detectChanges();
+ const metaAlertService = TestBed.get(MetaAlertService);
+ const router = TestBed.get(Router);
+ spyOn(component, 'processAddToAlert').and.callThrough();
+ spyOn(component, 'updateSelectedAlertStatus');
+ spyOn(router, 'navigateByUrl');
+ const actionsButton = fixture.debugElement.nativeElement.querySelector('[data-qe-id="dropdown-menu-button"');
+ actionsButton.click();
+ const processAddToAlertButton = fixture.debugElement.nativeElement.querySelector('[data-qe-id="action-add-to-alert-button"');
+ processAddToAlertButton.dispatchEvent(new Event('click'));
+ fixture.detectChanges();
+ expect(component.processAddToAlert).toHaveBeenCalled();
+ expect(metaAlertService.selectedAlerts).toEqual(component.selectedAlerts);
+ expect(router.navigateByUrl).toHaveBeenCalledWith('/alerts-list(dialog:add-to-meta-alert)');
+ });
+ });
+
+ describe('table configuration', () => {
+ it('should reconfigure rows when value is emitted to configRowsChange', () => {
+ const configureTableService = TestBed.get(ConfigureTableService);
+ spyOn(component, 'updatePollingInterval');
+ spyOn(component, 'search');
+ spyOn(configureTableService, 'saveTableMetaData').and.callThrough();
+ component.onConfigRowsChange({
+ values: {
+ pageSize: 10,
+ refreshInterval: 1000
+ },
+ triggerQuery: true
+ });
+
+ expect(component.tableMetaData.size).toEqual(10);
+ expect(configureTableService.saveTableMetaData).toHaveBeenCalledWith(component.tableMetaData);
+ expect(component.search).toHaveBeenCalled();
+ });
});
});
diff --git a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.ts b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.ts
index 1bb7a04..9e7f0b8 100755
--- a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.ts
+++ b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.ts
@@ -201,13 +201,6 @@ export class AlertsListComponent implements OnInit, OnDestroy {
}
}
- getColumnNamesForQuery() {
- let fieldNames = this.alertsColumns.map(columnMetadata => columnMetadata.name);
- fieldNames = fieldNames.filter(name => !(name === 'id' || name === 'alert_status'));
- fieldNames.push(this.globalConfig['threat.score.field.name']);
- return fieldNames;
- }
-
ngOnDestroy() {
this.autoPollingSvc.onDestroy();
this.removeAlertChangedListner();
@@ -442,15 +435,6 @@ export class AlertsListComponent implements OnInit, OnDestroy {
saveCurrentSearch(savedSearch: SaveSearch) {
if (this.queryBuilder.query !== '*') {
- if (!savedSearch) {
- savedSearch = new SaveSearch();
- savedSearch.searchRequest = this.queryBuilder.searchRequest;
- savedSearch.tableColumns = this.alertsColumns;
- savedSearch.filters = this.queryBuilder.filters;
- savedSearch.searchRequest.query = '';
- savedSearch.name = this.queryBuilder.generateNameForSearchRequest();
- }
-
this.saveSearchService.saveAsRecentSearches(savedSearch).subscribe(() => {
});
}