Skip to content

Commit

Permalink
Add pytest with some example events
Browse files Browse the repository at this point in the history
The lambda now has some local tests we can use to confirm we're handling
events correctly.

We also have a new env var supported that allows us to enable incoming
event logging for all events.  Even if this is off, failure to handle an
event should still result in the event message being logged.
  • Loading branch information
jinnko committed Feb 12, 2019
1 parent b926f04 commit cea9a3f
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 4 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ terraform.tfstate
*.tfstate*
terraform.tfvars
functions/*.zip
functions/pytest.ini
25 changes: 21 additions & 4 deletions functions/notify_slack.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from __future__ import print_function
from urllib.error import HTTPError
import os, boto3, json, base64
import urllib.request, urllib.parse
import logging
Expand Down Expand Up @@ -59,6 +60,11 @@ def notify_slack(message, region):
"icon_emoji": slack_emoji,
"attachments": []
}

if isinstance(message, str):
logging.warning("message is a string, assuming it's JSON and decoding")
message = json.loads(message)

if "AlarmName" in message:
notification = cloudwatch_notification(message, region)
payload['text'] = "AWS CloudWatch notification - " + message["AlarmName"]
Expand All @@ -69,14 +75,25 @@ def notify_slack(message, region):

data = urllib.parse.urlencode({"payload": json.dumps(payload)}).encode("utf-8")
req = urllib.request.Request(slack_url)
urllib.request.urlopen(req, data)

try:
result = urllib.request.urlopen(req, data)
return result.getcode(), result.info()

except HTTPError as e:
logging.error("{}: result".format(e))
return e.getcode(), e.info()


def lambda_handler(event, context):
if 'LOG_EVENTS' in os.environ and os.environ['LOG_EVENTS'] == 'True':
logging.warning('Event logging enabled: `{}`'.format(event))

message = event['Records'][0]['Sns']['Message']
region = event['Records'][0]['Sns']['TopicArn'].split(":")[3]
notify_slack(message, region)
code, info = notify_slack(message, region)

return message
if code is not None and code != 200:
logging.error("Error: received status `{}` using event `{}` and context `{}`".format(info, event, context))

#notify_slack({"AlarmName":"Example","AlarmDescription":"Example alarm description.","AWSAccountId":"000000000000","NewStateValue":"ALARM","NewStateReason":"Threshold Crossed","StateChangeTime":"2017-01-12T16:30:42.236+0000","Region":"EU - Ireland","OldStateValue":"OK"}, "eu-west-1")
return code, info
67 changes: 67 additions & 0 deletions functions/notify_slack_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/usr/bin/env pytest

import notify_slack
import pytest
from os import environ

events = (
(
{
"Records": [
{
"EventSource": "aws:sns",
"EventVersion": "1.0",
"EventSubscriptionArn": "arn:aws:sns:eu-west-2:735598076380:service-updates:d29b4e2c-6840-9c4e-ceac-17128efcc337",
"Sns": {
"Type": "Notification",
"MessageId": "f86e3c5b-cd17-1ab8-80e9-c0776d4f1e7a",
"TopicArn": "arn:aws:sns:eu-west-2:735598076380:service-updates",
"Subject": "OK: \"DBMigrationRequired\" in EU (London)",
"Message": "{\"AlarmName\":\"DBMigrationRequired\",\"AlarmDescription\":\"App is reporting \\\"A JPA error occurred (Unable to build EntityManagerFactory)\\\"\",\"AWSAccountId\":\"735598076380\",\"NewStateValue\":\"OK\",\"NewStateReason\":\"Threshold Crossed: 1 datapoint [1.0 (12/02/19 15:44:00)] was not less than the threshold (1.0).\",\"StateChangeTime\":\"2019-02-12T15:45:24.006+0000\",\"Region\":\"EU (London)\",\"OldStateValue\":\"ALARM\",\"Trigger\":{\"MetricName\":\"DBMigrationRequired\",\"Namespace\":\"LogMetrics\",\"StatisticType\":\"Statistic\",\"Statistic\":\"SUM\",\"Unit\":null,\"Dimensions\":[],\"Period\":60,\"EvaluationPeriods\":1,\"ComparisonOperator\":\"LessThanThreshold\",\"Threshold\":1.0,\"TreatMissingData\":\"- TreatMissingData: NonBreaching\",\"EvaluateLowSampleCountPercentile\":\"\"}}",
"Timestamp": "2019-02-12T15:45:24.091Z",
"SignatureVersion": "1",
"Signature": "WMYdVRN7ECNXMWZ0faRDD4fSfALW5MISB6O//LMd/LeSQYNQ/1eKYEE0PM1SHcH+73T/f/eVHbID/F203VZaGECQTD4LVA4B0DGAEY39LVbWdPTCHIDC6QCBV5ScGFZcROBXMe3UBWWMQAVTSWTE0eP526BFUTecaDFM4b9HMT4NEHWa4A2TA7d888JaVKKdSVNTd4bGS6Q2XFG1MOb652BRAHdARO7A6//2/47JZ5COM6LR0/V7TcOYCBZ20CRF6L5XLU46YYL3I1PNGKbEC1PIeVDVJVPcA17NfUbFXWYBX8LHfM4O7ZbGAPaGffDYLFWM6TX1Y6fQ01OSMc21OdUGV6HQR01e%==",
"SigningCertUrl": "https://sns.eu-west-2.amazonaws.com/SimpleNotificationService-7dd85a2b76adaa8dd603b7a0c9150589.pem",
"UnsubscribeUrl": "https://sns.eu-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:eu-west-2:735598076380:service-updates:d29b4e2c-6840-9c4e-ceac-17128efcc337",
"MessageAttributes": {}
}
}
]
}
),
(
{
"AlarmName": "Example",
"AlarmDescription": "Example alarm description.",
"AWSAccountId": "000000000000",
"NewStateValue": "ALARM",
"NewStateReason": "Threshold Crossed",
"StateChangeTime": "2017-01-12T16:30:42.236+0000",
"Region": "EU - Ireland",
"OldStateValue": "OK"
}
)
)


@pytest.fixture(scope='module', autouse=True)
def check_environment_variables():
required_environment_variables = ("SLACK_CHANNEL", "SLACK_EMOJI", "SLACK_USERNAME", "SLACK_WEBHOOK_URL")
missing_environment_variables = []
for k in required_environment_variables:
if k not in environ:
missing_environment_variables.append(k)

if len(missing_environment_variables) > 0:
pytest.exit('Missing environment variables: {}'.format(", ".join(missing_environment_variables)))


@pytest.mark.parametrize("event", events)
def test_lambda_handler(event):
if 'Records' in event:
(code, info) = notify_slack.lambda_handler(event, 'self-context')

else:
(code, info) = notify_slack.notify_slack(event, 'eu-west-1')

assert code == 200
8 changes: 8 additions & 0 deletions functions/pytest.ini.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[pytest]
addopts = --disable-pytest-warnings
env =
SLACK_CHANNEL=slack_testing_sandbox
SLACK_EMOJI=:aws:
SLACK_USERNAME=notify_slack_test
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/YOUR/WEBOOK/URL

4 changes: 4 additions & 0 deletions functions/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
boto3

pytest
pytest-env

0 comments on commit cea9a3f

Please sign in to comment.