def test_aggregate_alarm_creation(self, log_mock): """CLI - Adding CloudWatch metric alarm, aggregate""" alarm_info = { 'metric_target': 'aggregate', 'metric_name': 'TotalRecords', 'evaluation_periods': 1, 'alarm_description': '', 'alarm_name': 'Aggregate Unit Testing Total Records Alarm', 'period': 300, 'threshold': 100.0, 'statistic': 'Sum', 'clusters': {}, 'comparison_operator': 'LessThanThreshold' } with nested(*self.mocked_opens): config = CLIConfig() config.add_metric_alarm(alarm_info) log_mock.assert_called_with('Successfully added \'%s\' metric alarm to ' '\'conf/global.json\'.', 'Aggregate Unit Testing Total Records Alarm')
def test_cluster_alarm_creation(self, log_mock): """CLI - Adding CloudWatch metric alarm, cluster""" alarm_info = { 'metric_target': 'cluster', 'metric_name': 'TotalRecords', 'evaluation_periods': 1, 'alarm_description': '', 'alarm_name': 'Prod Unit Testing Total Records Alarm', 'period': 300, 'threshold': 100.0, 'statistic': 'Sum', 'clusters': set(['prod']), 'comparison_operator': 'LessThanThreshold' } with nested(*self.mocked_opens): config = CLIConfig() config.add_metric_alarm(alarm_info) log_mock.assert_called_with('Successfully added \'%s\' metric alarm for the ' '\'%s\' function to \'conf/clusters/%s.json\'.', 'Prod Unit Testing Total Records Alarm', 'rule_processor', 'prod')
class TestCLIConfig(object): """Test class for CLIConfig""" def __init__(self): self.config = None self.fs_patcher = None def setup(self): """Setup before each method""" config_data = basic_streamalert_config() self.fs_patcher = fake_filesystem_unittest.Patcher() self.fs_patcher.setUp() self.fs_patcher.fs.CreateFile('/conf/global.json', contents=json.dumps( config_data['global'])) self.fs_patcher.fs.CreateFile('/conf/lambda.json', contents=json.dumps( config_data['lambda'])) self.fs_patcher.fs.CreateFile('/conf/clusters/prod.json', contents=json.dumps( config_data['clusters']['prod'])) # Create the config instance after creating the fake filesystem so that # CLIConfig uses our mocked config files instead of the real ones. self.config = CLIConfig() def teardown(self): """Teardown after each method""" self.fs_patcher.tearDown() def test_load_config(self): """CLI - Load config""" assert_equal(self.config['global']['account']['prefix'], 'unit-testing') @patch('logging.Logger.error') @patch('stream_alert_cli.config.CLIConfig.write') def test_toggle_metric(self, write_mock, log_mock): """CLI - Metric toggling""" self.config.toggle_metrics(True, [], ['athena_partition_refresh']) write_mock.assert_called() del self.config.config['lambda']['athena_partition_refresh_config'] self.config.toggle_metrics(True, [], ['athena_partition_refresh']) log_mock.assert_called_with( 'No Athena configuration found; please initialize first.') self.config.toggle_metrics(True, ['prod'], ['alert_processor']) write_mock.assert_called() def test_aggregate_alarm_exists(self): """CLI - Aggregate alarm check""" result = self.config._alarm_exists( 'Aggregate Unit Testing Failed Parses Alarm') assert_true(result) def test_cluster_alarm_exists(self): """CLI - Aggregate alarm check""" result = self.config._alarm_exists( 'Prod Unit Testing Failed Parses Alarm') assert_true(result) @patch('stream_alert_cli.config.CLIConfig.write', Mock()) @patch('logging.Logger.info') def test_cluster_alarm_creation(self, log_mock): """CLI - Adding CloudWatch metric alarm, cluster""" alarm_info = { 'metric_target': 'cluster', 'metric_name': 'TotalRecords', 'evaluation_periods': 1, 'alarm_description': '', 'alarm_name': 'Prod Unit Testing Total Records Alarm', 'period': 300, 'threshold': 100.0, 'statistic': 'Sum', 'clusters': set(['prod']), 'comparison_operator': 'LessThanThreshold' } self.config.add_metric_alarm(alarm_info) log_mock.assert_called_with( 'Successfully added \'%s\' metric alarm for the ' '\'%s\' function to \'conf/clusters/%s.json\'.', 'Prod Unit Testing Total Records Alarm', 'rule_processor', 'prod') @patch('stream_alert_cli.config.CLIConfig.write', Mock()) @patch('logging.Logger.info') def test_aggregate_alarm_creation(self, log_mock): """CLI - Adding CloudWatch metric alarm, aggregate""" alarm_info = { 'metric_target': 'aggregate', 'metric_name': 'TotalRecords', 'evaluation_periods': 1, 'alarm_description': '', 'alarm_name': 'Aggregate Unit Testing Total Records Alarm', 'period': 300, 'threshold': 100.0, 'statistic': 'Sum', 'clusters': {}, 'comparison_operator': 'LessThanThreshold' } self.config.add_metric_alarm(alarm_info) log_mock.assert_called_with( 'Successfully added \'%s\' metric alarm to ' '\'conf/global.json\'.', 'Aggregate Unit Testing Total Records Alarm') @patch('logging.Logger.info') @patch('stream_alert_cli.config.CLIConfig.write') def test_add_threat_intel_with_table_name(self, write_mock, log_mock): """CLI - Add Threat Intel config with default dynamodb table name""" threat_intel_info = { 'command': 'threat_intel', 'debug': 'False', 'dynamodb_table': 'my_ioc_table', 'subcommand': 'enable' } self.config.add_threat_intel(threat_intel_info) expected_config = {'enabled': True, 'dynamodb_table': 'my_ioc_table'} assert_equal(self.config['global']['threat_intel'], expected_config) write_mock.assert_called() log_mock.assert_called() @patch('logging.Logger.info') @patch('stream_alert_cli.config.CLIConfig.write') def test_add_threat_intel_without_table_name(self, write_mock, log_mock): """CLI - Add Threat Intel config without dynamodb table name from cli""" threat_intel_info = { 'command': 'threat_intel', 'debug': 'False', 'subcommand': 'enable' } self.config.add_threat_intel(threat_intel_info) expected_config = { 'enabled': True, 'dynamodb_table': 'unit-testing_streamalert_threat_intel_downloader' } assert_equal(self.config['global']['threat_intel'], expected_config) write_mock.assert_called() log_mock.assert_called() @patch('logging.Logger.info') @patch('stream_alert_cli.config.CLIConfig.write') def test_add_threat_intel_downloader(self, write_mock, log_mock): """CLI - Add Threat Intel Downloader config""" del self.config['lambda']['threat_intel_downloader_config'] ti_downloader_info = { 'autoscale': True, 'command': 'threat_intel_downloader', 'debug': False, 'interval': 'rate(1 day)', 'memory': '128', 'subcommand': 'enable', 'timeout': '240', 'table_wcu': 25, 'max_read_capacity': 100, 'min_read_capacity': 5, 'target_utilization': 70 } result = self.config.add_threat_intel_downloader(ti_downloader_info) assert_true(result) expected_config = { 'autoscale': True, 'enabled': True, 'current_version': '$LATEST', 'handler': 'stream_alert.threat_intel_downloader.main.handler', 'interval': 'rate(1 day)', 'ioc_filters': [], 'ioc_keys': [], 'ioc_types': [], 'excluded_sub_types': [], 'log_level': 'info', 'memory': '128', 'source_bucket': 'unit-testing.streamalert.source', 'source_current_hash': '<auto_generated>', 'source_object_key': '<auto_generated>', 'third_party_libraries': ['requests'], 'table_rcu': 10, 'table_wcu': 25, 'timeout': '240', 'max_read_capacity': 100, 'min_read_capacity': 5, 'target_utilization': 70 } assert_equal(self.config['lambda']['threat_intel_downloader_config'], expected_config) write_mock.assert_called() log_mock.assert_not_called() # no config changed if threat intel downloader already been enabled via CLI result = self.config.add_threat_intel_downloader(ti_downloader_info) assert_false(result) write_mock.assert_called_once() log_mock.assert_called_with( 'Threat Intel Downloader has been enabled. ' 'Please edit config/lambda.json if you want to ' 'change lambda function settings.')
class TestCLIConfig(object): """Test class for CLIConfig""" def __init__(self): self.config = None self.fs_patcher = None def setup(self): """Setup before each method""" config_data = basic_streamalert_config() self.fs_patcher = fake_filesystem_unittest.Patcher() self.fs_patcher.setUp() self.fs_patcher.fs.create_file('/conf/global.json', contents=json.dumps( config_data['global'])) self.fs_patcher.fs.create_file('/conf/threat_intel.json', contents=json.dumps( config_data['threat_intel'])) self.fs_patcher.fs.create_file('/conf/normalized_types.json', contents=json.dumps( config_data['normalized_types'])) self.fs_patcher.fs.create_file('/conf/lambda.json', contents=json.dumps( config_data['lambda'])) self.fs_patcher.fs.create_file('/conf/clusters/prod.json', contents=json.dumps( config_data['clusters']['prod'])) # Create the config instance after creating the fake filesystem so that # CLIConfig uses our mocked config files instead of the real ones. self.config = CLIConfig() def teardown(self): """Teardown after each method""" self.fs_patcher.tearDown() def test_load_config(self): """CLI - Load config""" assert_equal(self.config['global']['account']['prefix'], 'unit-testing') def test_toggle_metric(self): """CLI - Metric toggling""" self.config.toggle_metrics('athena_partition_refresh', enabled=True) assert_equal( self.config['lambda']['athena_partition_refresh_config'] ['enable_custom_metrics'], True) self.config.toggle_metrics('alert_processor', enabled=False) assert_equal( self.config['lambda']['alert_processor_config'] ['enable_custom_metrics'], False) def test_aggregate_alarm_exists(self): """CLI - Aggregate alarm check""" result = self.config._alarm_exists( 'Aggregate Unit Testing Failed Parses Alarm') assert_true(result) def test_cluster_alarm_exists(self): """CLI - Cluster alarm check""" result = self.config._alarm_exists( 'Prod Unit Testing Failed Parses Alarm') assert_true(result) def test_cluster_alarm_creation(self): """CLI - Adding CloudWatch metric alarm, cluster""" alarm_info = { 'function': 'classifier', 'metric_name': 'TotalRecords', 'evaluation_periods': 1, 'alarm_description': '', 'alarm_name': 'Prod Unit Testing Total Records Alarm', 'period': 300, 'threshold': 100.0, 'statistic': 'Sum', 'clusters': {'prod'}, 'comparison_operator': 'LessThanThreshold' } expected_result = { 'Prod Unit Testing Total Records Alarm': { 'metric_name': 'Classifier-TotalRecords-PROD', 'evaluation_periods': 1, 'alarm_description': '', 'period': 300, 'threshold': 100.0, 'statistic': 'Sum', 'comparison_operator': 'LessThanThreshold' }, 'Prod Unit Testing Failed Parses Alarm': { 'alarm_description': '', 'comparison_operator': 'GreaterThanOrEqualToThreshold', 'evaluation_periods': 1, 'metric_name': 'Classifier-FailedParses-PROD', 'period': 300, 'statistic': 'Sum', 'threshold': 1.0 } } self.config.add_metric_alarm(alarm_info) result = (self.config['clusters']['prod']['modules']['stream_alert'] ['classifier_config']['custom_metric_alarms']) assert_equal(result, expected_result) def test_aggregate_alarm_creation(self): """CLI - Adding CloudWatch metric alarm, aggregate""" alarm_info = { 'function': 'classifier', 'metric_name': 'TotalRecords', 'evaluation_periods': 1, 'alarm_description': '', 'alarm_name': 'Aggregate Unit Testing Total Records Alarm', 'period': 300, 'threshold': 100.0, 'statistic': 'Sum', 'comparison_operator': 'LessThanThreshold' } expected_result = { 'Aggregate Unit Testing Total Records Alarm': { 'metric_name': 'Classifier-TotalRecords', 'evaluation_periods': 1, 'alarm_description': '', 'period': 300, 'threshold': 100.0, 'statistic': 'Sum', 'comparison_operator': 'LessThanThreshold' } } self.config.add_metric_alarm(alarm_info) result = self.config['lambda']['classifier_config'][ 'custom_metric_alarms'] assert_equal(result, expected_result) def test_add_threat_intel_with_table_name(self): """CLI - Add Threat Intel config with default dynamodb table name""" threat_intel_info = { 'command': 'threat-intel', 'debug': 'False', 'dynamodb_table_name': 'my_ioc_table', 'enable': True } self.config.add_threat_intel(threat_intel_info) expected_config = { 'enabled': True, 'dynamodb_table_name': 'my_ioc_table', 'excluded_iocs': {}, 'normalized_ioc_types': { 'ip': ['sourceAddress', 'destinationAddress'] } } assert_equal(self.config['threat_intel'], expected_config) def test_add_threat_intel_without_table_name(self): """CLI - Add Threat Intel config without dynamodb table name from cli""" threat_intel_info = { 'command': 'threat-intel', 'debug': 'False', 'dynamodb_table_name': None, 'enable': True } del self.config['threat_intel']['dynamodb_table_name'] self.config.add_threat_intel(threat_intel_info) expected_config = { 'enabled': True, 'dynamodb_table_name': 'unit-testing_streamalert_threat_intel_downloader', 'excluded_iocs': {}, 'normalized_ioc_types': { 'ip': ['sourceAddress', 'destinationAddress'] } } assert_equal(self.config['threat_intel'], expected_config) @patch('logging.Logger.info') @patch('stream_alert_cli.config.CLIConfig.write') def test_add_threat_intel_downloader(self, write_mock, log_mock): """CLI - Add Threat Intel Downloader config""" del self.config['lambda']['threat_intel_downloader_config'] ti_downloader_info = { 'autoscale': True, 'command': 'threat_intel_downloader', 'debug': False, 'interval': 'rate(1 day)', 'memory': '128', 'subcommand': 'enable', 'timeout': '240', 'table_wcu': 25, 'max_read_capacity': 100, 'min_read_capacity': 5, 'target_utilization': 70 } result = self.config.add_threat_intel_downloader(ti_downloader_info) assert_true(result) expected_config = { 'autoscale': True, 'enabled': True, 'interval': 'rate(1 day)', 'ioc_filters': [], 'ioc_keys': [], 'ioc_types': [], 'excluded_sub_types': [], 'log_level': 'info', 'memory': '128', 'third_party_libraries': ['requests'], 'table_rcu': 10, 'table_wcu': 25, 'timeout': '240', 'max_read_capacity': 100, 'min_read_capacity': 5, 'target_utilization': 70 } assert_equal(self.config['lambda']['threat_intel_downloader_config'], expected_config) write_mock.assert_called() log_mock.assert_not_called() # no config changed if threat intel downloader already been enabled via CLI result = self.config.add_threat_intel_downloader(ti_downloader_info) assert_false(result) write_mock.assert_called_once() log_mock.assert_called_with( 'Threat Intel Downloader has been enabled. ' 'Please edit config/lambda.json if you want to ' 'change lambda function settings.')