blob: 228125d3a8b5d87145aae10ab1d52cefbab7919d [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { Inject } from '@angular/core';
import { Observable, throwError } from 'rxjs';
import { Router, ActivatedRoute, Params } from '@angular/router';
import { HttpClient, HttpResponse } from '@angular/common/http';
import {
SensorParserConfigComponent,
Pane,
KafkaStatus
} from './sensor-parser-config.component';
import { StellarService } from '../../service/stellar.service';
import { SensorParserConfigService } from '../../service/sensor-parser-config.service';
import { KafkaService } from '../../service/kafka.service';
import { KafkaTopic } from '../../model/kafka-topic';
import { GrokValidationService } from '../../service/grok-validation.service';
import { MetronAlerts } from '../../shared/metron-alerts';
import { SensorParserConfig } from '../../model/sensor-parser-config';
import { ParseMessageRequest } from '../../model/parse-message-request';
import { SensorParserContext } from '../../model/sensor-parser-context';
import { AuthenticationService } from '../../service/authentication.service';
import { FieldTransformer } from '../../model/field-transformer';
import { SensorParserConfigModule } from './sensor-parser-config.module';
import { SensorEnrichmentConfigService } from '../../service/sensor-enrichment-config.service';
import { SensorEnrichmentConfig } from '../../model/sensor-enrichment-config';
import { SensorIndexingConfigService } from '../../service/sensor-indexing-config.service';
import { IndexingConfigurations } from '../../model/sensor-indexing-config';
import { of } from 'rxjs';
import { HdfsService } from '../../service/hdfs.service';
import { RestError } from '../../model/rest-error';
import { RiskLevelRule } from '../../model/risk-level-rule';
import {AppConfigService} from '../../service/app-config.service';
import {MockAppConfigService} from '../../service/mock.app-config.service';
class MockRouter {
navigateByUrl(url: string) {}
}
class MockActivatedRoute {
private name: string;
params: Observable<Params>;
setNameForTest(name: string) {
this.name = name;
this.params = Observable.create(observer => {
observer.next({ id: this.name });
observer.complete();
});
}
}
class MockSensorParserConfigService extends SensorParserConfigService {
private name: string;
private sensorParserConfig: SensorParserConfig;
private parsedMessage: any;
private postedSensorParserConfig: SensorParserConfig;
private throwError: boolean;
public post(
name: string,
sensorParserConfig: SensorParserConfig
): Observable<SensorParserConfig> {
if (this.throwError) {
let error = new RestError();
error.message = 'SensorParserConfig post error';
return throwError(error);
}
this.postedSensorParserConfig = sensorParserConfig;
return Observable.create(observer => {
observer.next(sensorParserConfig);
observer.complete();
});
}
public get(name: string): Observable<SensorParserConfig> {
return Observable.create(observer => {
observer.next(this.sensorParserConfig);
observer.complete();
});
}
public getAll(): Observable<{}> {
return Observable.create(observer => {
let results = {};
results[this.name] = this.sensorParserConfig;
observer.next(results);
observer.complete();
});
}
public getAvailableParsers(): Observable<{}> {
return Observable.create(observer => {
observer.next({
Bro: 'org.apache.metron.parsers.bro.BasicBroParser',
Grok: 'org.apache.metron.parsers.GrokParser'
});
observer.complete();
});
}
public parseMessage(
parseMessageRequest: ParseMessageRequest
): Observable<{}> {
return Observable.create(observer => {
observer.next(this.parsedMessage);
observer.complete();
});
}
public setSensorParserConfig(
name: string,
sensorParserConfig: SensorParserConfig
) {
this.name = name;
this.sensorParserConfig = sensorParserConfig;
}
public setParsedMessage(parsedMessage: any) {
this.parsedMessage = parsedMessage;
}
public setThrowError(throwError: boolean) {
this.throwError = throwError;
}
public getPostedSensorParserConfig() {
return this.postedSensorParserConfig;
}
}
class MockSensorIndexingConfigService extends SensorIndexingConfigService {
private name: string;
private postedIndexingConfigurations: IndexingConfigurations;
private sensorIndexingConfig: IndexingConfigurations;
private throwError: boolean;
public post(
name: string,
sensorIndexingConfig: IndexingConfigurations
): Observable<IndexingConfigurations> {
if (this.throwError) {
let error = new RestError();
error.message = 'IndexingConfigurations post error';
return throwError(error);
}
this.postedIndexingConfigurations = sensorIndexingConfig;
return Observable.create(observer => {
observer.next(sensorIndexingConfig);
observer.complete();
});
}
public get(name: string): Observable<IndexingConfigurations> {
if (this.sensorIndexingConfig === null) {
let error = new RestError();
error.message = 'IndexingConfigurations get error';
return throwError(error);
}
return Observable.create(observer => {
if (name === this.name) {
observer.next(this.sensorIndexingConfig);
}
observer.complete();
});
}
public setSensorIndexingConfig(name: string, result: IndexingConfigurations) {
this.name = name;
this.sensorIndexingConfig = result;
}
public setThrowError(throwError: boolean) {
this.throwError = throwError;
}
public getPostedIndexingConfigurations(): IndexingConfigurations {
return this.postedIndexingConfigurations;
}
}
class MockKafkaService extends KafkaService {
private name: string;
private kafkaTopic: KafkaTopic;
private kafkaTopicForPost: KafkaTopic;
private sampleData = { key1: 'value1', key2: 'value2' };
public setKafkaTopic(name: string, kafkaTopic: KafkaTopic) {
this.name = name;
this.kafkaTopic = kafkaTopic;
}
public setSampleData(name: string, sampleData?: any) {
this.name = name;
this.sampleData = sampleData;
}
public sample(name: string): Observable<string> {
if (this.sampleData === null) {
return throwError(new RestError());
}
return Observable.create(observer => {
if (name === this.name) {
observer.next(JSON.stringify(this.sampleData));
}
observer.complete();
});
}
public get(name: string): Observable<KafkaTopic> {
if (this.kafkaTopic === null) {
return throwError(new RestError());
}
return Observable.create(observer => {
if (name === this.name) {
observer.next(this.kafkaTopic);
}
observer.complete();
});
}
public post(k: KafkaTopic): Observable<KafkaTopic> {
this.kafkaTopicForPost = k;
console.log('called post MockKafkaService: ' + this.kafkaTopicForPost);
return Observable.create(observer => {
observer.next({});
observer.complete();
});
}
public getKafkaTopicForPost(): KafkaTopic {
console.log('Called get MockKafkaService: ' + this.kafkaTopicForPost);
return this.kafkaTopicForPost;
}
}
class MockGrokValidationService extends GrokValidationService {
private path: string;
private contents: string;
public setContents(path: string, contents: string) {
this.path = path;
this.contents = contents;
}
public list(): Observable<string[]> {
return Observable.create(observer => {
observer.next({
BASE10NUM:
'(?<![0-9.+-])(?>[+-]?(?:(?:[0-9]+(?:\\.[0-9]+)?)|(?:\\.[0-9]+)))',
BASE16FLOAT:
'\\b(?<![0-9A-Fa-f.])(?:[+-]?(?:0x)?(?:(?:[0-9A-Fa-f]+(?:\\.[0-9A-Fa-f]*)?)|(?:\\.[0-9A-Fa-f]+)))\\b',
BASE16NUM: '(?<![0-9A-Fa-f])(?:[+-]?(?:0x)?(?:[0-9A-Fa-f]+))',
CISCOMAC: '(?:(?:[A-Fa-f0-9]{4}\\.){2}[A-Fa-f0-9]{4})',
COMMONMAC: '(?:(?:[A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2})',
DATA: '.*?'
});
observer.complete();
});
}
public getStatement(path: string): Observable<string> {
if (this.contents === null) {
return throwError('Error');
}
return Observable.create(observer => {
if (path === this.path) {
observer.next(this.contents);
}
observer.complete();
});
}
}
class MockHdfsService extends HdfsService {
private fileList: string[];
private path: string;
private contents: string;
private postedContents: string;
public setFileList(path: string, fileList: string[]) {
this.path = path;
this.fileList = fileList;
}
public setContents(path: string, contents: string) {
this.path = path;
this.contents = contents;
}
public list(path: string): Observable<string[]> {
if (this.fileList === null) {
return throwError('Error');
}
return Observable.create(observer => {
if (path === this.path) {
observer.next(this.fileList);
}
observer.complete();
});
}
public read(path: string): Observable<string> {
if (this.contents === null) {
return throwError('Error');
}
return Observable.create(observer => {
if (path === this.path) {
observer.next(this.contents);
}
observer.complete();
});
}
public post(path: string, contents: string): Observable<{}> {
if (this.contents === null) {
let error = new RestError();
error.message = 'HDFS post Error';
return throwError(error);
}
this.postedContents = contents;
return Observable.create(observer => {
observer.next(contents);
observer.complete();
});
}
public deleteFile(path: string): Observable<HttpResponse<{}>> {
return Observable.create(observer => {
observer.next({});
observer.complete();
});
}
public getPostedContents() {
return this.postedContents;
}
}
class MockAuthenticationService extends AuthenticationService {
public getCurrentUser(options: {}): Observable<HttpResponse<{}>> {
let responseOptions: {} = { body: 'user' };
let response: HttpResponse<{}> = new HttpResponse(responseOptions);
return of(response);
}
}
class MockTransformationValidationService extends StellarService {
private transformationValidationResult: any;
private transformationValidationForValidate: SensorParserContext;
public setTransformationValidationResultForTest(
transformationValidationResult: any
): void {
this.transformationValidationResult = transformationValidationResult;
}
public getTransformationValidationForValidate(): SensorParserContext {
return this.transformationValidationForValidate;
}
public validate(t: SensorParserContext): Observable<{}> {
this.transformationValidationForValidate = t;
return Observable.create(observer => {
observer.next(this.transformationValidationResult);
observer.complete();
});
}
}
export class MockSensorEnrichmentConfigService {
private name: string;
private sensorEnrichmentConfig: SensorEnrichmentConfig;
private postedSensorEnrichmentConfig: SensorEnrichmentConfig;
private throwError: boolean;
public setSensorEnrichmentConfig(
name: string,
sensorEnrichmentConfig: SensorEnrichmentConfig
) {
this.name = name;
this.sensorEnrichmentConfig = sensorEnrichmentConfig;
}
public get(name: string): Observable<SensorEnrichmentConfig> {
if (this.sensorEnrichmentConfig === null) {
let error = new RestError();
error.message = 'SensorEnrichmentConfig get error';
return throwError(error);
}
return Observable.create(observer => {
if (name === this.name) {
observer.next(this.sensorEnrichmentConfig);
}
observer.complete();
});
}
public post(
name: string,
sensorEnrichmentConfig: SensorEnrichmentConfig
): Observable<SensorEnrichmentConfig> {
if (this.throwError) {
let error = new RestError();
error.message = 'SensorEnrichmentConfig post error';
return throwError(error);
}
this.postedSensorEnrichmentConfig = sensorEnrichmentConfig;
return Observable.create(observer => {
observer.next(sensorEnrichmentConfig);
observer.complete();
});
}
public setThrowError(throwError: boolean) {
this.throwError = throwError;
}
public getPostedSensorEnrichmentConfig() {
return this.postedSensorEnrichmentConfig;
}
}
describe('Component: SensorParserConfig', () => {
let component: SensorParserConfigComponent;
let fixture: ComponentFixture<SensorParserConfigComponent>;
let sensorParserConfigService: MockSensorParserConfigService;
let sensorEnrichmentConfigService: MockSensorEnrichmentConfigService;
let sensorIndexingConfigService: MockSensorIndexingConfigService;
let transformationValidationService: MockTransformationValidationService;
let kafkaService: MockKafkaService;
let hdfsService: MockHdfsService;
let grokValidationService: MockGrokValidationService;
let activatedRoute: MockActivatedRoute;
let metronAlerts: MetronAlerts;
let router: MockRouter;
let squidSensorParserConfig: any = {
parserClassName: 'org.apache.metron.parsers.GrokParser',
sensorTopic: 'squid',
parserConfig: {
grokPath: '/apps/metron/patterns/squid',
patternLabel: 'SQUID_DELIMITED',
timestampField: 'timestamp'
},
fieldTransformations: [
{
input: [],
output: ['full_hostname', 'domain_without_subdomains', 'hostname'],
transformation: 'STELLAR',
config: {
full_hostname: 'URL_TO_HOST(url)',
domain_without_subdomains: 'DOMAIN_REMOVE_SUBDOMAINS(full_hostname)'
}
}
]
};
let squidSensorEnrichmentConfig = {
enrichment: {
fieldMap: {
geo: ['ip_dst_addr'],
host: ['ip_dst_addr'],
whois: [],
stellar: { config: { group1: {} } }
},
fieldToTypeMap: {},
config: {}
},
threatIntel: {
threatIntel: {
fieldMap: { hbaseThreatIntel: ['ip_dst_addr'] },
fieldToTypeMap: { ip_dst_addr: ['malicious_ip'] }
}
}
};
let squidIndexingConfigurations = {
hdfs: {
index: 'squid',
batchSize: 5,
enabled: true
},
elasticsearch: {
index: 'squid',
batchSize: 10,
enabled: true
},
solr: {
index: 'squid',
batchSize: 1,
enabled: false
}
};
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [SensorParserConfigModule],
providers: [
MetronAlerts,
{ provide: HttpClient },
{
provide: SensorParserConfigService,
useClass: MockSensorParserConfigService
},
{
provide: SensorIndexingConfigService,
useClass: MockSensorIndexingConfigService
},
{ provide: KafkaService, useClass: MockKafkaService },
{ provide: HdfsService, useClass: MockHdfsService },
{ provide: GrokValidationService, useClass: MockGrokValidationService },
{
provide: StellarService,
useClass: MockTransformationValidationService
},
{ provide: ActivatedRoute, useClass: MockActivatedRoute },
{ provide: Router, useClass: MockRouter },
{ provide: AuthenticationService, useClass: MockAuthenticationService },
{
provide: SensorEnrichmentConfigService,
useClass: MockSensorEnrichmentConfigService
},
{ provide: AppConfigService, useClass: MockAppConfigService }
]
});
fixture = TestBed.createComponent(SensorParserConfigComponent);
component = fixture.componentInstance;
sensorParserConfigService = TestBed.get(SensorParserConfigService);
sensorIndexingConfigService = TestBed.get(SensorIndexingConfigService);
transformationValidationService = TestBed.get(StellarService);
kafkaService = TestBed.get(KafkaService);
hdfsService = TestBed.get(HdfsService);
grokValidationService = TestBed.get(GrokValidationService);
sensorEnrichmentConfigService = TestBed.get(SensorEnrichmentConfigService);
activatedRoute = TestBed.get(ActivatedRoute);
metronAlerts = TestBed.get(MetronAlerts);
router = TestBed.get(Router);
}));
afterEach(() => {
fixture.destroy();
})
it('should create an instance of SensorParserConfigComponent', async(() => {
expect(component).toBeDefined();
}));
it('should handle ngOnInit', async(() => {
spyOn(component, 'init');
spyOn(component, 'createForms');
spyOn(component, 'getAvailableParsers');
activatedRoute.setNameForTest('squid');
component.ngOnInit();
expect(component.init).toHaveBeenCalledWith('squid');
expect(component.createForms).toHaveBeenCalled();
expect(component.getAvailableParsers).toHaveBeenCalled();
}));
it('should createForms', async(() => {
component.sensorParserConfig = Object.assign(
new SensorParserConfig(),
squidSensorParserConfig
);
component.createForms();
expect(Object.keys(component.sensorConfigForm.controls).length).toEqual(17);
expect(
Object.keys(component.transformsValidationForm.controls).length
).toEqual(2);
expect(component.showAdvancedParserConfiguration).toEqual(true);
component.sensorParserConfig.parserConfig = {};
component.showAdvancedParserConfiguration = false;
component.createForms();
expect(component.showAdvancedParserConfiguration).toEqual(false);
}));
it('should getAvailableParsers', async(() => {
component.getAvailableParsers();
expect(component.availableParsers).toEqual({
Bro: 'org.apache.metron.parsers.bro.BasicBroParser',
Grok: 'org.apache.metron.parsers.GrokParser'
});
expect(component.availableParserNames).toEqual(['Bro', 'Grok']);
}));
it('should init', async(() => {
sensorParserConfigService.setSensorParserConfig(
'squid',
squidSensorParserConfig
);
component.init('new');
let expectedSensorParserConfig = new SensorParserConfig();
expectedSensorParserConfig.parserClassName =
'org.apache.metron.parsers.GrokParser';
expect(component.sensorParserConfig).toEqual(expectedSensorParserConfig);
expect(component.sensorEnrichmentConfig).toEqual(
new SensorEnrichmentConfig()
);
expect(component.indexingConfigurations).toEqual(
new IndexingConfigurations()
);
expect(component.editMode).toEqual(false);
expect(component.currentSensors).toEqual(['squid']);
spyOn(component, 'getKafkaStatus');
let sensorParserConfig = Object.assign(
new SensorParserConfig(),
squidSensorParserConfig
);
sensorParserConfigService.setSensorParserConfig(
'squid',
sensorParserConfig
);
sensorEnrichmentConfigService.setSensorEnrichmentConfig(
'squid',
Object.assign(new SensorEnrichmentConfig(), squidSensorEnrichmentConfig)
);
sensorIndexingConfigService.setSensorIndexingConfig(
'squid',
Object.assign(new IndexingConfigurations(), squidIndexingConfigurations)
);
hdfsService.setContents(
'/apps/metron/patterns/squid',
'SQUID_DELIMITED grok statement'
);
component.init('squid');
expect(component.sensorParserConfig).toEqual(
Object.assign(new SensorParserConfig(), squidSensorParserConfig)
);
expect(component.sensorNameValid).toEqual(true);
expect(component.getKafkaStatus).toHaveBeenCalled();
expect(component.showAdvancedParserConfiguration).toEqual(true);
expect(component.grokStatement).toEqual('SQUID_DELIMITED grok statement');
expect(component.patternLabel).toEqual('SQUID_DELIMITED');
expect(component.sensorEnrichmentConfig).toEqual(
Object.assign(new SensorEnrichmentConfig(), squidSensorEnrichmentConfig)
);
expect(component.indexingConfigurations).toEqual(
Object.assign(new IndexingConfigurations(), squidIndexingConfigurations)
);
component.sensorParserConfig.parserConfig['grokPath'] = '/patterns/squid';
hdfsService.setContents('/patterns/squid', null);
grokValidationService.setContents(
'/patterns/squid',
'SQUID grok statement from classpath'
);
component.init('squid');
expect(component.grokStatement).toEqual(
'SQUID grok statement from classpath'
);
spyOn(metronAlerts, 'showErrorMessage');
sensorEnrichmentConfigService.setSensorEnrichmentConfig('squid', null);
component.init('squid');
expect(metronAlerts.showErrorMessage).toHaveBeenCalledWith(
'SensorEnrichmentConfig get error'
);
sensorIndexingConfigService.setSensorIndexingConfig('squid', null);
component.init('squid');
expect(metronAlerts.showErrorMessage).toHaveBeenCalledWith(
'IndexingConfigurations get error'
);
grokValidationService.setContents('/patterns/squid', null);
component.init('squid');
expect(metronAlerts.showErrorMessage).toHaveBeenCalledWith(
'Could not find grok statement in HDFS or classpath at /patterns/squid'
);
sensorParserConfig = new SensorParserConfig();
sensorParserConfig.sensorTopic = 'bro';
sensorParserConfigService.setSensorParserConfig('bro', sensorParserConfig);
component.showAdvancedParserConfiguration = false;
component.init('bro');
expect(component.showAdvancedParserConfiguration).toEqual(false);
}));
it('should getMessagePrefix', async(() => {
component.getAvailableParsers();
expect(component.getMessagePrefix()).toEqual('Created');
component.editMode = true;
expect(component.getMessagePrefix()).toEqual('Modified');
}));
it('should handle onSetKafkaTopic', async(() => {
spyOn(component, 'getKafkaStatus');
component.onSetKafkaTopic();
expect(component.getKafkaStatus).not.toHaveBeenCalled();
component.sensorParserConfig.sensorTopic = 'bro';
component.onSetKafkaTopic();
expect(component.kafkaTopicValid).toEqual(true);
expect(component.getKafkaStatus).toHaveBeenCalled();
}));
it('should handle onSetSensorName', async(() => {
component.onSetSensorName();
expect(component.sensorNameValid).toEqual(false);
component.sensorName = 'squid';
component.currentSensors = ['squid'];
component.onSetSensorName();
expect(component.sensorNameUnique).toEqual(false);
expect(component.sensorNameValid).toEqual(false);
component.sensorName = 'squidUnique';
component.onSetSensorName();
expect(component.sensorNameUnique).toEqual(true);
expect(component.sensorNameValid).toEqual(true);
}));
it('sensor name should be validated agains special characters', () => {
component.sensorName = 'squidWithSpecChar@';
component.onSetSensorName();
expect(component.sensorNameNoSpecChars).toEqual(false);
expect(component.sensorNameValid).toEqual(false);
component.sensorName = 'squidWithSpecChar#';
component.onSetSensorName();
expect(component.sensorNameNoSpecChars).toEqual(false);
expect(component.sensorNameValid).toEqual(false);
component.sensorName = 'squidWithSpecChar/';
component.onSetSensorName();
expect(component.sensorNameNoSpecChars).toEqual(false);
expect(component.sensorNameValid).toEqual(false);
component.sensorName = 'squidWithSpecChar?';
component.onSetSensorName();
expect(component.sensorNameNoSpecChars).toEqual(false);
expect(component.sensorNameValid).toEqual(false);
component.sensorName = 'squidWithSpecChar?$&%';
component.onSetSensorName();
expect(component.sensorNameNoSpecChars).toEqual(false);
expect(component.sensorNameValid).toEqual(false);
});
it('sensor name validation should accept dash and lowdash chars', () => {
component.sensorName = 'squidWithSpecChar-';
component.onSetSensorName();
expect(component.sensorNameNoSpecChars).toEqual(true);
expect(component.sensorNameValid).toEqual(true);
component.sensorName = 'squidWithSpecChar_';
component.onSetSensorName();
expect(component.sensorNameNoSpecChars).toEqual(true);
expect(component.sensorNameValid).toEqual(true);
})
it('should handle onParserTypeChange', async(() => {
spyOn(component, 'hidePane');
component.onParserTypeChange();
expect(component.hidePane).not.toHaveBeenCalled();
component.sensorParserConfig.parserClassName =
'org.apache.metron.parsers.GrokParser';
component.onParserTypeChange();
expect(component.parserClassValid).toEqual(true);
expect(component.hidePane).not.toHaveBeenCalled();
component.sensorParserConfig.parserClassName =
'org.apache.metron.parsers.bro.BasicBroParser';
component.onParserTypeChange();
expect(component.hidePane).toHaveBeenCalledWith(Pane.GROK);
}));
it('isGrokStatementValid should validate grokStatement', async(() => {
expect(component.isGrokStatementValid()).toEqual(false);
component.grokStatement = '';
expect(component.isGrokStatementValid()).toEqual(false);
component.grokStatement = 'grok statement';
expect(component.isGrokStatementValid()).toEqual(true);
}));
it('should handle isConfigValid', async(() => {
expect(component.isConfigValid()).toEqual(false);
component.sensorNameValid = true;
component.kafkaTopicValid = true;
component.parserClassValid = true;
expect(component.isConfigValid()).toEqual(true);
component.sensorParserConfig.parserClassName =
'org.apache.metron.parsers.GrokParser';
expect(component.isConfigValid()).toEqual(false);
component.grokStatement = 'grok statement';
expect(component.isConfigValid()).toEqual(true);
}));
it('should getKafkaStatus', async(() => {
component.getKafkaStatus();
expect(component.currentKafkaStatus).toEqual(null);
component.sensorParserConfig.sensorTopic = 'squid';
kafkaService.setKafkaTopic('squid', null);
component.getKafkaStatus();
expect(component.currentKafkaStatus).toEqual(KafkaStatus.NO_TOPIC);
kafkaService.setKafkaTopic('squid', new KafkaTopic());
kafkaService.setSampleData('squid', null);
component.getKafkaStatus();
expect(component.currentKafkaStatus).toEqual(KafkaStatus.NOT_EMITTING);
kafkaService.setSampleData('squid', 'message');
component.getKafkaStatus();
expect(component.currentKafkaStatus).toEqual(KafkaStatus.EMITTING);
}));
it('should getTransforms', async(() => {
expect(component.getTransforms()).toEqual('0 Transformations Applied');
component.sensorParserConfig.fieldTransformations.push(
Object.assign(new FieldTransformer(), { output: ['field1', 'field2'] })
);
component.sensorParserConfig.fieldTransformations.push(
Object.assign(new FieldTransformer(), { output: ['field3'] })
);
expect(component.getTransforms()).toEqual('3 Transformations Applied');
}));
it('should handle onSaveGrokStatement', async(() => {
component.sensorName = 'squid';
component.onSaveGrokStatement('grok statement');
expect(component.grokStatement).toEqual('grok statement');
expect(component.sensorParserConfig.parserConfig['grokPath']).toEqual(
'/apps/metron/patterns/squid'
);
component.sensorParserConfig.parserConfig['grokPath'] = '/patterns/squid';
component.onSaveGrokStatement('grok statement');
expect(component.sensorParserConfig.parserConfig['grokPath']).toEqual(
'/apps/metron/patterns/squid'
);
component.sensorParserConfig.parserConfig['grokPath'] = '/custom/grok/path';
component.onSaveGrokStatement('grok statement');
expect(component.sensorParserConfig.parserConfig['grokPath']).toEqual(
'/custom/grok/path'
);
}));
it('should onSavePatternLabel', async(() => {
component.onSavePatternLabel('PATTERN_LABEL');
expect(component.patternLabel).toEqual('PATTERN_LABEL');
expect(component.sensorParserConfig.parserConfig['patternLabel']).toEqual(
'PATTERN_LABEL'
);
}));
it('should goBack', async(() => {
activatedRoute.setNameForTest('new');
router.navigateByUrl = jasmine.createSpy('navigateByUrl');
component.goBack();
expect(router.navigateByUrl).toHaveBeenCalledWith('/sensors');
}));
it('should save sensor configuration', async(() => {
let fieldTransformer = Object.assign(new FieldTransformer(), {
input: [],
output: ['url_host'],
transformation: 'MTL',
config: { url_host: 'TO_LOWER(URL_TO_HOST(url))' }
});
let sensorParserConfigSave: SensorParserConfig = new SensorParserConfig();
sensorParserConfigSave.sensorTopic = 'squid';
sensorParserConfigSave.parserClassName =
'org.apache.metron.parsers.GrokParser';
sensorParserConfigSave.parserConfig['grokPath'] =
'/apps/metron/patterns/squid';
sensorParserConfigSave.fieldTransformations = [fieldTransformer];
activatedRoute.setNameForTest('new');
sensorParserConfigService.setThrowError(true);
spyOn(metronAlerts, 'showSuccessMessage');
spyOn(metronAlerts, 'showErrorMessage');
component.sensorParserConfig.sensorTopic = 'squid';
component.sensorParserConfig.parserClassName =
'org.apache.metron.parsers.GrokParser';
component.sensorParserConfig.parserConfig['grokPath'] =
'/apps/metron/patterns/squid';
component.sensorParserConfig.fieldTransformations = [fieldTransformer];
component.onSave();
expect(metronAlerts.showErrorMessage['calls'].mostRecent().args[0]).toEqual(
'Unable to save sensor config: SensorParserConfig post error'
);
component.sensorEnrichmentConfig = Object.assign(
new SensorEnrichmentConfig(),
squidSensorEnrichmentConfig
);
component.indexingConfigurations = Object.assign(
new IndexingConfigurations(),
squidIndexingConfigurations
);
sensorParserConfigService.setThrowError(false);
hdfsService.setContents(
'/apps/metron/patterns/squid',
'SQUID grok statement'
);
component.grokStatement = 'SQUID grok statement';
component.onSave();
expect(sensorParserConfigService.getPostedSensorParserConfig()).toEqual(
sensorParserConfigSave
);
expect(
sensorEnrichmentConfigService.getPostedSensorEnrichmentConfig()
).toEqual(
Object.assign(new SensorEnrichmentConfig(), squidSensorEnrichmentConfig)
);
expect(
sensorIndexingConfigService.getPostedIndexingConfigurations()
).toEqual(
Object.assign(new IndexingConfigurations(), squidIndexingConfigurations)
);
expect(hdfsService.getPostedContents()).toEqual('SQUID grok statement');
hdfsService.setContents('/apps/metron/patterns/squid', null);
component.onSave();
expect(metronAlerts.showErrorMessage['calls'].mostRecent().args[0]).toEqual(
'HDFS post Error'
);
sensorEnrichmentConfigService.setThrowError(true);
component.onSave();
expect(metronAlerts.showErrorMessage['calls'].mostRecent().args[0]).toEqual(
'Created Sensor parser config but unable to save enrichment configuration: SensorEnrichmentConfig post error'
);
sensorIndexingConfigService.setThrowError(true);
component.onSave();
expect(metronAlerts.showErrorMessage['calls'].mostRecent().args[0]).toEqual(
'Created Sensor parser config but unable to save indexing configuration: IndexingConfigurations post error'
);
}));
it('should getTransformationCount', async(() => {
let transforms = [
Object.assign(new FieldTransformer(), {
input: ['method'],
output: null,
transformation: 'REMOVE',
config: {
condition: 'exists(method) and method == "foo"'
}
}),
Object.assign(new FieldTransformer(), {
input: [],
output: ['method', 'status_code', 'url'],
transformation: 'STELLAR',
config: {
method: 'TO_UPPER(method)',
status_code: 'TO_LOWER(code)',
url: 'TO_STRING(TRIM(url))'
}
})
];
expect(component.getTransformationCount()).toEqual(0);
fixture.componentInstance.sensorParserConfig.fieldTransformations = transforms;
expect(component.getTransformationCount()).toEqual(3);
fixture.componentInstance.sensorParserConfig.fieldTransformations = [
transforms[0]
];
expect(component.getTransformationCount()).toEqual(0);
}));
it('should getEnrichmentCount', async(() => {
component.sensorEnrichmentConfig.enrichment.fieldMap['geo'] = [
'ip_src_addr',
'ip_dst_addr'
];
component.sensorEnrichmentConfig.enrichment.fieldToTypeMap[
'hbaseenrichment'
] = ['ip_src_addr', 'ip_dst_addr'];
expect(component.getEnrichmentCount()).toEqual(4);
}));
it('should getThreatIntelCount', async(() => {
component.sensorEnrichmentConfig.threatIntel.fieldToTypeMap[
'hbaseenrichment'
] = ['ip_src_addr', 'ip_dst_addr'];
expect(component.getThreatIntelCount()).toEqual(2);
}));
it('should getRuleCount', async(() => {
let rule1 = Object.assign(new RiskLevelRule(), {
name: 'rule1',
rule: 'some rule',
score: 50
});
let rule2 = Object.assign(new RiskLevelRule(), {
name: 'rule2',
rule: 'some other rule',
score: 80
});
component.sensorEnrichmentConfig.threatIntel.triageConfig.riskLevelRules.push(
rule1
);
component.sensorEnrichmentConfig.threatIntel.triageConfig.riskLevelRules.push(
rule2
);
expect(component.getRuleCount()).toEqual(2);
}));
it('should showPane', async(() => {
component.showPane(Pane.GROK);
expect(component.showGrokValidator).toEqual(true);
expect(component.showFieldSchema).toEqual(false);
expect(component.showRawJson).toEqual(false);
component.showPane(Pane.FIELDSCHEMA);
expect(component.showGrokValidator).toEqual(false);
expect(component.showFieldSchema).toEqual(true);
expect(component.showRawJson).toEqual(false);
component.showPane(Pane.RAWJSON);
expect(component.showGrokValidator).toEqual(false);
expect(component.showFieldSchema).toEqual(false);
expect(component.showRawJson).toEqual(true);
}));
it('should hidePane', async(() => {
component.hidePane(Pane.GROK);
expect(component.showGrokValidator).toEqual(false);
expect(component.showFieldSchema).toEqual(false);
expect(component.showRawJson).toEqual(false);
component.hidePane(Pane.FIELDSCHEMA);
expect(component.showGrokValidator).toEqual(false);
expect(component.showFieldSchema).toEqual(false);
expect(component.showRawJson).toEqual(false);
component.hidePane(Pane.RAWJSON);
expect(component.showGrokValidator).toEqual(false);
expect(component.showFieldSchema).toEqual(false);
expect(component.showRawJson).toEqual(false);
}));
it('should handle onShowGrokPane', async(() => {
spyOn(component, 'showPane');
component.sensorName = 'squid';
component.onShowGrokPane();
expect(component.patternLabel).toEqual('SQUID');
expect(component.showPane).toHaveBeenCalledWith(component.pane.GROK);
component.patternLabel = 'PATTERN_LABEL';
component.onShowGrokPane();
expect(component.patternLabel).toEqual('PATTERN_LABEL');
}));
it('should handle onRawJsonChanged', async(() => {
spyOn(component.sensorFieldSchema, 'createFieldSchemaRows');
component.onRawJsonChanged();
expect(
component.sensorFieldSchema.createFieldSchemaRows
).toHaveBeenCalled();
}));
it('should handle onAdvancedConfigFormClose', async(() => {
component.onAdvancedConfigFormClose();
expect(component.showAdvancedParserConfiguration).toEqual(false);
}));
it('should be timestamp by default', () => {
expect(component.sensorParserConfig.timestampField).toEqual('timestamp');
});
it('should be invalid if timestamp field is empty', () => {
component.sensorNameValid = true;
component.kafkaTopicValid = true;
component.parserClassValid = true;
component.grokStatement = 'grokStatement';
component.sensorParserConfig = new SensorParserConfig();
component.sensorParserConfig.parserClassName = 'org.apache.metron.parsers.GrokParser'
component.sensorParserConfig.timestampField = '';
expect(component.isConfigValid()).toEqual(false);
component.sensorParserConfig.timestampField = 'timestamp';
expect(component.isConfigValid()).toEqual(true);
});
});