"""Test logs logic.""" from random import random from time import time from unittest.mock import MagicMock, patch import boto3 from moto import mock_logs import pytest from cloudwatch_logs import config from cloudwatch_logs.api import flask_cache from cloudwatch_logs.logic import logs def create_mock_group_stream(group_name, stream_name): """Create mock group and stream for testing.""" client = boto3.client('logs') client.create_log_group( logGroupName=group_name, tags={ 'string': 'test' } ) client.create_log_stream( logGroupName=group_name, logStreamName=stream_name ) def put_sample_log(group_name, stream_name): """Put a sample message to log stream.""" client = boto3.client('logs') result = client.put_log_events( logGroupName=group_name, logStreamName=stream_name, logEvents=[ { 'timestamp': int(time() * 1000), 'message': 'this is test message' }, ] ) return result @pytest.fixture def reset_cache(): """Reset cache before each test.""" flask_cache.clear() @mock_logs def test_get_next_token(monkeypatch): """Test get_next_token should be same as what was provided on write.""" monkeypatch.setattr(logs, 'get_from_cache', MagicMock(return_value=None)) group_name = 'foo' stream_name = 'bar' create_mock_group_stream(group_name, stream_name) expected = put_sample_log(group_name, stream_name) actual = logs.get_next_token(group_name, stream_name) assert actual assert actual == str(expected.get('nextSequenceToken')) def test_get_from_cache(reset_cache): """Test cache get.""" expected = random() key = 'key_{}'.format(expected) flask_cache.set(key, expected) assert logs.get_from_cache(key) == expected assert logs.get_from_cache('dummy') is None def test_set_to_cache(reset_cache): """Test cache set.""" expected = random() key = 'key_{}'.format(expected) logs.set_to_cache(key, expected) assert flask_cache.get(key) == expected @mock_logs def test_write_cloudwatch_log(monkeypatch): """Test write_cloudwatch_log.""" monkeypatch.setattr(logs, 'get_from_cache', MagicMock(return_value=None)) monkeypatch.setattr(logs, 'set_to_cache', MagicMock(return_value=None)) data = {'user': 'data', 'To': ['+011234567890']} sequence_token = 'test' group_name = 'foo' stream_name = 'bar' create_mock_group_stream(group_name, stream_name) result = logs.write_cloudwatch_log( data, sequence_token, group_name, stream_name) actuals = result.message assert 'nextSequenceToken' in actuals assert 'ResponseMetadata' in actuals assert 200 == actuals['ResponseMetadata']['HTTPStatusCode'] logs.set_to_cache.assert_called_with( stream_name, actuals['nextSequenceToken']) @patch('cloudwatch_logs.logic.logs.api.Event') @patch('cloudwatch_logs.logic.logs.api.Metric') @patch('cloudwatch_logs.logic.logs.initialize') def test_write_datadog_log_success(init_mock, metric_mock, event_mock): """Test write_datadog_log.""" expected_api = {'for all': 'status'} expected_err = {'only for': 'error'} metric_mock.send.return_value = expected_api event_mock.create.return_value = expected_err data = { 'user': 'data', 'To': ['+011234567890'], 'From': ['ORCH'], 'SmsStatus': ['sent'], } actual = logs.write_datadog_log(data) assert actual assert actual.message == expected_api metric_mock.send.assert_called_once_with( metric=config.TWILIO_DATADOG_METRIC, points=1, host=config.TWILIO_DATADOG_HOST, tags=['source:API', 'status:sent'] ) event_mock.create.assert_not_called() @patch('cloudwatch_logs.logic.logs.api.Event') @patch('cloudwatch_logs.logic.logs.api.Metric') @patch('cloudwatch_logs.logic.logs.initialize') def test_write_datadog_log_sms_error(init_mock, metric_mock, event_mock): """Test write_datadog_log when twilio sms failed.""" expected_api = {'for all': 'status'} expected_err = {'only for': 'error'} metric_mock.send.return_value = expected_api event_mock.create.return_value = expected_err data = { 'user': 'data', 'To': ['+011234567890'], 'From': ['ORCH'], 'SmsStatus': ['error'], } actual = logs.write_datadog_log(data) assert actual assert actual.message == expected_api metric_mock.send.assert_called_once_with( metric=config.TWILIO_DATADOG_METRIC, points=1, host=config.TWILIO_DATADOG_HOST, tags=['source:API', 'status:error'] ) event_mock.create.assert_called_once() @patch('cloudwatch_logs.logic.logs.initialize') def test_write_datadog_log_exception(init_mock): """Test write_datadog_log when datadog init fails.""" init_mock.side_effect = Exception('some error') data = { 'user': 'data', 'To': ['+011234567890'], 'From': ['ORCH'], 'SmsStatus': ['dummy'], } actual = logs.write_datadog_log(data) assert actual.status == 200 assert actual.message == {'error': 'some error'}