Mitch Garnaat

A bunch of changes to support new unit testing strategy with placebo. More tests to come.

Showing 42 changed files with 649 additions and 262 deletions
......@@ -3,6 +3,7 @@ python:
- "2.7"
- "3.3"
- "3.4"
- "3.5"
install:
- pip install -r requirements.txt
- pip install coverage python-coveralls
......
......@@ -16,18 +16,18 @@ import logging
import jmespath
import boto3
import placebo
LOG = logging.getLogger(__name__)
_session_cache = {}
class AWSClient(object):
def __init__(self, service_name, region_name, profile_name):
def __init__(self, service_name, session):
self._service_name = service_name
self._region_name = region_name
self._profile_name = profile_name
self._session = session
self.client = self._create_client()
@property
......@@ -35,20 +35,11 @@ class AWSClient(object):
return self._service_name
@property
def region_name(self):
return self._region_name
@property
def profile_name(self):
return self._profile_name
def session(self):
return self._session
def _create_client(self):
global recording_path
session = boto3.session.Session(
region_name=self._region_name, profile_name=self._profile_name)
if recording_path:
placebo.attach(session)
client = session.client(self._service_name)
client = self._session.client(self._service_name)
return client
def call(self, op_name, query=None, **kwargs):
......@@ -93,17 +84,15 @@ class AWSClient(object):
return data
_client_cache = {}
recording_path = None
def create_session(profile_name, region_name):
global _session_cache
session_key = '{}:{}'.format(profile_name, region_name)
if session_key not in _session_cache:
session = boto3.session.Session(
region_name=region_name, profile_name=profile_name)
_session_cache[session_key] = session
return _session_cache[session_key]
def create_client(service_name, context):
global _client_cache
client_key = '{}:{}:{}'.format(service_name, context.region,
context.profile)
if client_key not in _client_cache:
client = AWSClient(service_name, context.region,
context.profile)
_client_cache[client_key] = client
return _client_cache[client_key]
def create_client(service_name, session):
return AWSClient(service_name, session)
......
......@@ -24,6 +24,8 @@ import kappa.policy
import kappa.role
import kappa.awsclient
import placebo
LOG = logging.getLogger(__name__)
DebugFmtString = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
......@@ -38,10 +40,15 @@ class Context(object):
self.set_logger('kappa', logging.DEBUG)
else:
self.set_logger('kappa', logging.INFO)
kappa.awsclient.recording_path = recording_path
self._load_cache()
self.config = yaml.load(config_file)
self.environment = environment
profile = self.config['environments'][self.environment]['profile']
region = self.config['environments'][self.environment]['region']
self.session = kappa.awsclient.create_session(profile, region)
if recording_path:
self.pill = placebo.attach(self.session, recording_path)
self.pill.record()
self.policy = kappa.policy.Policy(
self, self.config['environments'][self.environment])
self.role = kappa.role.Role(
......
......@@ -48,7 +48,8 @@ class KinesisEventSource(EventSource):
def __init__(self, context, config):
super(KinesisEventSource, self).__init__(context, config)
self._lambda = kappa.awsclient.create_client('kinesis', context)
self._lambda = kappa.awsclient.create_client(
'kinesis', context.session)
def _get_uuid(self, function):
uuid = None
......@@ -150,7 +151,7 @@ class S3EventSource(EventSource):
def __init__(self, context, config):
super(S3EventSource, self).__init__(context, config)
self._s3 = kappa.awsclient.create_client('s3', config)
self._s3 = kappa.awsclient.create_client('s3', context.session)
def _make_notification_id(self, function_name):
return 'Kappa-%s-notification' % function_name
......@@ -213,7 +214,7 @@ class SNSEventSource(EventSource):
def __init__(self, context, config):
super(SNSEventSource, self).__init__(context, config)
self._sns = kappa.awsclient.create_client('sns', context)
self._sns = kappa.awsclient.create_client('sns', context.session)
def _make_notification_id(self, function_name):
return 'Kappa-%s-notification' % function_name
......
......@@ -33,7 +33,7 @@ class Function(object):
self._context = context
self._config = config
self._lambda_client = kappa.awsclient.create_client(
'lambda', context)
'lambda', context.session)
self._response = None
self._log = None
......
......@@ -26,7 +26,8 @@ class Log(object):
def __init__(self, context, log_group_name):
self._context = context
self.log_group_name = log_group_name
self._log_client = kappa.awsclient.create_client('logs', context)
self._log_client = kappa.awsclient.create_client(
'logs', context.session)
def _check_for_log_group(self):
LOG.debug('checking for log group')
......
......@@ -26,7 +26,8 @@ class Policy(object):
def __init__(self, context, config):
self._context = context
self._config = config
self._iam_client = kappa.awsclient.create_client('iam', self._context)
self._iam_client = kappa.awsclient.create_client(
'iam', self._context.session)
self._arn = self._config['policy'].get('arn', None)
@property
......@@ -75,10 +76,11 @@ class Policy(object):
def _find_all_policies(self):
try:
response = self._iam_client.call(
'list_policies')
'list_policies', PathPrefix=self.path)
except Exception:
LOG.exception('Error listing policies')
return response['Policies']
response = {}
return response.get('Policies', list())
def _list_versions(self):
try:
......
......@@ -40,7 +40,8 @@ class Role(object):
def __init__(self, context, config):
self._context = context
self._config = config
self._iam_client = kappa.awsclient.create_client('iam', context)
self._iam_client = kappa.awsclient.create_client(
'iam', context.session)
self._arn = None
@property
......@@ -64,7 +65,8 @@ class Role(object):
response = self._iam_client.call('list_roles')
except Exception:
LOG.exception('Error listing roles')
return response['Roles']
response = {}
return response.get('Roles', list())
def exists(self):
for role in self._find_all_roles():
......
boto3>=1.2.2
placebo>=0.3.0
placebo>=0.4.1
click==5.1
PyYAML>=3.11
mock>=1.0.1
......
.kappa/
kappa.yml
......@@ -6,7 +6,7 @@ import os
requires = [
'boto3>=1.2.2',
'placebo>=0.3.0',
'placebo>=0.4.1',
'click>=5.0',
'PyYAML>=3.11'
]
......@@ -36,10 +36,10 @@ setup(
'Natural Language :: English',
'License :: OSI Approved :: Apache Software License',
'Programming Language :: Python',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4'
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5'
),
)
......
[foobar]
aws_access_key_id = foo
aws_secret_access_key = bar
{
"Statement":[
{"Condition":
{"ArnLike":{"AWS:SourceArn":"arn:aws:sns:us-east-1:123456789012:lambda_topic"}},
"Resource":"arn:aws:lambda:us-east-1:123456789023:function:messageStore",
"Action":"lambda:invokeFunction",
"Principal":{"Service":"sns.amazonaws.com"},
"Sid":"sns invoke","Effect":"Allow"
}],
"Id":"default",
"Version":"2012-10-17"
}
dev: {config_md5: 3ccd0a5630fa4e0d0effeb9de0b551a3, policy_md5: 12273b7917929c02cfc755f4700e1e2b,
zip_md5: b6605fd4990542106fa95b62ea62d70e}
def handler(event, context):
return {'status': 'success'}
No preview for this file type
---
name: kappa-simple
environments:
dev:
profile: foobar
region: us-west-2
policy:
resources:
- arn: arn:aws:logs:*:*:*
actions:
- "*"
lambda:
description: Foo the Bar
handler: simple.handler
runtime: python2.7
memory_size: 256
timeout: 3
import inspect
import mock
import tests.unit.responses as responses
class MockAWS(object):
def __init__(self, profile=None, region=None):
self.response_map = {}
for name, value in inspect.getmembers(responses):
if name.startswith('__'):
continue
if '_' in name:
service_name, request_name = name.split('_', 1)
if service_name not in self.response_map:
self.response_map[service_name] = {}
self.response_map[service_name][request_name] = value
def create_client(self, client_name):
client = None
if client_name in self.response_map:
client = mock.Mock()
for request in self.response_map[client_name]:
response = self.response_map[client_name][request]
setattr(client, request, mock.Mock(side_effect=response))
return client
def get_aws(context):
return MockAWS()
This diff is collapsed. Click to expand it.
{
"status_code": 200,
"data": {
"ResponseMetadata": {
"HTTPStatusCode": 200,
"RequestId": "1276680a-a219-11e5-8386-d3391e1d709e"
}
}
}
\ No newline at end of file
{
"status_code": 200,
"data": {
"Policy": {
"PolicyName": "kappa-simple_dev",
"CreateDate": {
"hour": 4,
"__class__": "datetime",
"month": 12,
"second": 46,
"microsecond": 302000,
"year": 2015,
"day": 14,
"minute": 13
},
"AttachmentCount": 0,
"IsAttachable": true,
"PolicyId": "ANPAJ6USPUIU5QKQ7DWMG",
"DefaultVersionId": "v1",
"Path": "/kappa/",
"Arn": "arn:aws:iam::123456789012:policy/kappa/kappa-simple_dev",
"UpdateDate": {
"hour": 4,
"__class__": "datetime",
"month": 12,
"second": 46,
"microsecond": 302000,
"year": 2015,
"day": 14,
"minute": 13
}
},
"ResponseMetadata": {
"HTTPStatusCode": 200,
"RequestId": "11cdf3d8-a219-11e5-a392-d5ea3c3fc695"
}
}
}
{
"status_code": 200,
"data": {
"Role": {
"AssumeRolePolicyDocument": "%7B%0A%20%20%20%20%22Version%22%20%3A%20%222012-10-17%22%2C%0A%20%20%20%20%22Statement%22%3A%20%5B%20%7B%0A%20%20%20%20%20%20%20%20%22Effect%22%3A%20%22Allow%22%2C%0A%20%20%20%20%20%20%20%20%22Principal%22%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Service%22%3A%20%5B%20%22lambda.amazonaws.com%22%20%5D%0A%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%22Action%22%3A%20%5B%20%22sts%3AAssumeRole%22%20%5D%0A%20%20%20%20%7D%20%5D%0A%7D",
"RoleId": "AROAICWPJDQLUTEOHRQZO",
"CreateDate": {
"hour": 4,
"__class__": "datetime",
"month": 12,
"second": 46,
"microsecond": 988000,
"year": 2015,
"day": 14,
"minute": 13
},
"RoleName": "kappa-simple_dev",
"Path": "/kappa/",
"Arn": "arn:aws:iam::123456789012:role/kappa/kappa-simple_dev"
},
"ResponseMetadata": {
"HTTPStatusCode": 200,
"RequestId": "123d5777-a219-11e5-8386-d3391e1d709e"
}
}
}
{
"status_code": 200,
"data": {
"Role": {
"AssumeRolePolicyDocument": "%7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22lambda.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D",
"RoleId": "AROAICWPJDQLUTEOHRQZO",
"CreateDate": {
"hour": 4,
"__class__": "datetime",
"month": 12,
"second": 46,
"microsecond": 0,
"year": 2015,
"day": 14,
"minute": 13
},
"RoleName": "kappa-simple_dev",
"Path": "/kappa/",
"Arn": "arn:aws:iam::123456789012:role/kappa/kappa-simple_dev"
},
"ResponseMetadata": {
"HTTPStatusCode": 200,
"RequestId": "12dca49a-a219-11e5-9912-d70327f9be2c"
}
}
}
{
"status_code": 200,
"data": {
"Role": {
"AssumeRolePolicyDocument": "%7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22lambda.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D",
"RoleId": "AROAICWPJDQLUTEOHRQZO",
"CreateDate": {
"hour": 4,
"__class__": "datetime",
"month": 12,
"second": 46,
"microsecond": 0,
"year": 2015,
"day": 14,
"minute": 13
},
"RoleName": "kappa-simple_dev",
"Path": "/kappa/",
"Arn": "arn:aws:iam::123456789012:role/kappa/kappa-simple_dev"
},
"ResponseMetadata": {
"HTTPStatusCode": 200,
"RequestId": "1bd39022-a219-11e5-bb1e-6b18bfdcba09"
}
}
}
This diff is collapsed. Click to expand it.
{
"status_code": 200,
"data": {
"ResponseMetadata": {
"HTTPStatusCode": 200,
"RequestId": "1264405a-a219-11e5-ad54-c769aa17a0a1"
},
"IsTruncated": false,
"Policies": [
{
"PolicyName": "kappa-simple_dev",
"CreateDate": {
"hour": 4,
"__class__": "datetime",
"month": 12,
"second": 46,
"microsecond": 0,
"year": 2015,
"day": 14,
"minute": 13
},
"AttachmentCount": 0,
"IsAttachable": true,
"PolicyId": "ANPAJ6USPUIU5QKQ7DWMG",
"DefaultVersionId": "v1",
"Path": "/kappa/",
"Arn": "arn:aws:iam::123456789012:policy/kappa/kappa-simple_dev",
"UpdateDate": {
"hour": 4,
"__class__": "datetime",
"month": 12,
"second": 46,
"microsecond": 0,
"year": 2015,
"day": 14,
"minute": 13
}
},
{
"PolicyName": "FooBar15",
"CreateDate": {
"hour": 19,
"__class__": "datetime",
"month": 12,
"second": 15,
"microsecond": 0,
"year": 2015,
"day": 10,
"minute": 22
},
"AttachmentCount": 1,
"IsAttachable": true,
"PolicyId": "ANPAJ3MM445EFVC6OWPIO",
"DefaultVersionId": "v1",
"Path": "/kappa/",
"Arn": "arn:aws:iam::123456789012:policy/kappa/FooBar15",
"UpdateDate": {
"hour": 19,
"__class__": "datetime",
"month": 12,
"second": 15,
"microsecond": 0,
"year": 2015,
"day": 10,
"minute": 22
}
}
]
}
}
{
"status_code": 200,
"data": {
"ResponseMetadata": {
"HTTPStatusCode": 200,
"RequestId": "1b40516e-a219-11e5-bb1e-6b18bfdcba09"
},
"IsTruncated": false,
"Policies": [
{
"PolicyName": "kappa-simple_dev",
"CreateDate": {
"hour": 4,
"__class__": "datetime",
"month": 12,
"second": 46,
"microsecond": 0,
"year": 2015,
"day": 14,
"minute": 13
},
"AttachmentCount": 1,
"IsAttachable": true,
"PolicyId": "ANPAJ6USPUIU5QKQ7DWMG",
"DefaultVersionId": "v1",
"Path": "/kappa/",
"Arn": "arn:aws:iam::123456789012:policy/kappa/kappa-simple_dev",
"UpdateDate": {
"hour": 4,
"__class__": "datetime",
"month": 12,
"second": 46,
"microsecond": 0,
"year": 2015,
"day": 14,
"minute": 13
}
},
{
"PolicyName": "FooBar15",
"CreateDate": {
"hour": 19,
"__class__": "datetime",
"month": 12,
"second": 15,
"microsecond": 0,
"year": 2015,
"day": 10,
"minute": 22
},
"AttachmentCount": 1,
"IsAttachable": true,
"PolicyId": "ANPAJ3MM445EFVC6OWPIO",
"DefaultVersionId": "v1",
"Path": "/kappa/",
"Arn": "arn:aws:iam::123456789012:policy/kappa/FooBar15",
"UpdateDate": {
"hour": 19,
"__class__": "datetime",
"month": 12,
"second": 15,
"microsecond": 0,
"year": 2015,
"day": 10,
"minute": 22
}
}
]
}
}
{
"status_code": 200,
"data": {
"ResponseMetadata": {
"HTTPStatusCode": 200,
"RequestId": "120be6dd-a219-11e5-ad54-c769aa17a0a1"
},
"IsTruncated": false,
"Roles": [
{
"AssumeRolePolicyDocument": "%7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Sid%22%3A%22%22%2C%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22lambda.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D",
"RoleId": "AROAJC6I44KNC2N4C6DUO",
"CreateDate": {
"hour": 13,
"__class__": "datetime",
"month": 8,
"second": 29,
"microsecond": 0,
"year": 2015,
"day": 12,
"minute": 10
},
"RoleName": "FooBar1",
"Path": "/kappa/",
"Arn": "arn:aws:iam::123456789012:role/kappa/FooBar1"
},
{
"AssumeRolePolicyDocument": "%7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Sid%22%3A%22%22%2C%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22AWS%22%3A%22arn%3Aaws%3Aiam%3A%3A433502988969%3Aroot%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D",
"RoleId": "AROAIPICAZWCWSIUY6WBC",
"CreateDate": {
"hour": 6,
"__class__": "datetime",
"month": 5,
"second": 3,
"microsecond": 0,
"year": 2015,
"day": 5,
"minute": 31
},
"RoleName": "FooBar2",
"Path": "/",
"Arn": "arn:aws:iam::123456789012:role/FooBar2"
}
]
}
}
{
"status_code": 200,
"data": {
"ResponseMetadata": {
"HTTPStatusCode": 200,
"RequestId": "1b6a1fab-a219-11e5-bb1e-6b18bfdcba09"
},
"IsTruncated": false,
"Roles": [
{
"AssumeRolePolicyDocument": "%7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22lambda.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D",
"RoleId": "AROAICWPJDQLUTEOHRQZO",
"CreateDate": {
"hour": 4,
"__class__": "datetime",
"month": 12,
"second": 46,
"microsecond": 0,
"year": 2015,
"day": 14,
"minute": 13
},
"RoleName": "kappa-simple_dev",
"Path": "/kappa/",
"Arn": "arn:aws:iam::123456789012:role/kappa/kappa-simple_dev"
},
{
"AssumeRolePolicyDocument": "%7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Sid%22%3A%22%22%2C%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22AWS%22%3A%22arn%3Aaws%3Aiam%3A%3A123456789012%3Aroot%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%2C%22Condition%22%3A%7B%22StringEquals%22%3A%7B%22sts%3AExternalId%22%3A%22c196gvft3%22%7D%7D%7D%5D%7D",
"RoleId": "AROAJGQVUYMCJZYCM3MR4",
"CreateDate": {
"hour": 15,
"__class__": "datetime",
"month": 6,
"second": 2,
"microsecond": 0,
"year": 2015,
"day": 12,
"minute": 53
},
"RoleName": "kate-test-policy-role",
"Path": "/",
"Arn": "arn:aws:iam::123456789012:role/kate-test-policy-role"
}
]
}
}
{
"status_code": 201,
"data": {
"AliasArn": "arn:aws:lambda:us-west-2:123456789012:function:kappa-simple:dev",
"FunctionVersion": "12",
"Name": "dev",
"ResponseMetadata": {
"HTTPStatusCode": 201,
"RequestId": "1872d8ff-a219-11e5-9579-ab6c3f6de03e"
},
"Description": "For stage dev"
}
}
{
"status_code": 400,
"data": {
"ResponseMetadata": {
"HTTPStatusCode": 400,
"RequestId": "12ed468e-a219-11e5-89fa-9b1d3e60e617"
},
"Error": {
"Message": "The role defined for the task cannot be assumed by Lambda.",
"Code": "InvalidParameterValueException"
}
}
}
\ No newline at end of file
{
"status_code": 400,
"data": {
"ResponseMetadata": {
"HTTPStatusCode": 400,
"RequestId": "14375279-a219-11e5-b9da-196ca0eccf24"
},
"Error": {
"Message": "The role defined for the task cannot be assumed by Lambda.",
"Code": "InvalidParameterValueException"
}
}
}
\ No newline at end of file
{
"status_code": 400,
"data": {
"ResponseMetadata": {
"HTTPStatusCode": 400,
"RequestId": "158815a1-a219-11e5-b354-111009c28f60"
},
"Error": {
"Message": "The role defined for the task cannot be assumed by Lambda.",
"Code": "InvalidParameterValueException"
}
}
}
\ No newline at end of file
{
"status_code": 400,
"data": {
"ResponseMetadata": {
"HTTPStatusCode": 400,
"RequestId": "16d88a59-a219-11e5-abfc-a3c6c8e4d88f"
},
"Error": {
"Message": "The role defined for the task cannot be assumed by Lambda.",
"Code": "InvalidParameterValueException"
}
}
}
\ No newline at end of file
{
"status_code": 201,
"data": {
"CodeSha256": "JklpzNjuO6TLDiNe6nVYWeo1Imq6bF5uaMt2L0bqp5Y=",
"FunctionName": "kappa-simple",
"ResponseMetadata": {
"HTTPStatusCode": 201,
"RequestId": "1820256f-a219-11e5-acaa-ebe01320cf02"
},
"CodeSize": 948,
"MemorySize": 256,
"FunctionArn": "arn:aws:lambda:us-west-2:123456789012:function:kappa-simple",
"Version": "12",
"Role": "arn:aws:iam::123456789012:role/kappa/kappa-simple_dev",
"Timeout": 3,
"LastModified": "2015-12-14T04:13:56.737+0000",
"Handler": "simple.handler",
"Runtime": "python2.7",
"Description": "A very simple Kappa example"
}
}
{
"status_code": 404,
"data": {
"ResponseMetadata": {
"HTTPStatusCode": 404,
"RequestId": "12caa276-a219-11e5-bc80-bb0600635952"
},
"Error": {
"Message": "Function not found: arn:aws:lambda:us-west-2:860421987956:function:kappa-simple",
"Code": "ResourceNotFoundException"
}
}
}
\ No newline at end of file
{
"status_code": 200,
"data": {
"Code": {
"RepositoryType": "S3",
"Location": "https://awslambda-us-west-2-tasks.s3-us-west-2.amazonaws.com/snapshots/123456789012/kappa-simple-99dba060-c458-48c6-ab7b-501063603e69?x-amz-security-token=AQoDYXdzECQa4AOvxYmkiVqa3ost0drsHs84f3tyUBYSVQUm%2BVvFZgAqx9JDt55l4N4T%2FwH8302pH0ICUZfCRRfc%2FuWtukJsT33XIsG6Xw0Br8w00y07RRpZYQLiJqTXi0i2EFZ6LMIRsGBgKV%2BdufXXu7P9yfzqBiFUrfUD6fYeRNLdv34aXUDto0G0gTj3ZDv9gqO9q7YEXbeu1NI62cIfuEGph2ptFj5V1E%2BijK0h9XEW0mkfuomQt6oeii%2FkkNNm5tEyUlpeX17z1sbX3NYoqJrap0QdoqXkak%2BFPvJQG7hm7eJ40b2ymve9L3gvIOiKNzmQrzay77uEkYDNLxK89QMlYRtRG6vTHppdZzTVIooTFVdA6NSSvYHnjryStLA3VUnDG%2FsL9xAiHH8l4kzq%2ByvatF%2Fg8wTNXOdFxt0VMVkJVbwG%2FUex7juyEcRAJUGNaHBZNLPJVUL%2BfAQljCwJAnjXxD%2FpjEtyLi9YbdfLGywkBKccoKh7AmjJXwzT8TusWNKmmW0XJL%2Fn81NE84Ni9iVB8JHxRbwaJXT2ou0ytwn%2BIIlRcmwXSIwA3xm%2FXynUTfOuXZ3UMGuBlHtt45uKGJvvp5d6RQicK5q5LXFQgGxj5gUqgty0jPhPE%2BN%2BF8WUwSk3eNwPiwMgwOS4swU%3D&AWSAccessKeyId=ASIAIHZZJVPM3RQS3QOQ&Expires=1450067042&Signature=QeC65kDb6N4CNRGn9IiQNBSpl4g%3D"
},
"Configuration": {
"Version": "$LATEST",
"CodeSha256": "JklpzNjuO6TLDiNe6nVYWeo1Imq6bF5uaMt2L0bqp5Y=",
"FunctionName": "kappa-simple",
"MemorySize": 256,
"CodeSize": 948,
"FunctionArn": "arn:aws:lambda:us-west-2:123456789012:function:kappa-simple",
"Handler": "simple.handler",
"Role": "arn:aws:iam::123456789012:role/kappa/kappa-simple_dev",
"Timeout": 3,
"LastModified": "2015-12-14T04:13:56.737+0000",
"Runtime": "python2.7",
"Description": "A very simple Kappa example"
},
"ResponseMetadata": {
"HTTPStatusCode": 200,
"RequestId": "1bc69855-a219-11e5-990d-c158fa575e6a"
}
}
}
{
"status_code": 200,
"data": {
"ResponseMetadata": {
"HTTPStatusCode": 200,
"RequestId": "1860ff11-a219-11e5-b9da-196ca0eccf24"
},
"Versions": [
{
"Version": "$LATEST",
"CodeSha256": "JklpzNjuO6TLDiNe6nVYWeo1Imq6bF5uaMt2L0bqp5Y=",
"FunctionName": "kappa-simple",
"MemorySize": 256,
"CodeSize": 948,
"FunctionArn": "arn:aws:lambda:us-west-2:123456789012:function:kappa-simple:$LATEST",
"Handler": "simple.handler",
"Role": "arn:aws:iam::123456789012:role/kappa/kappa-simple_dev",
"Timeout": 3,
"LastModified": "2015-12-14T04:13:56.737+0000",
"Runtime": "python2.7",
"Description": "A very simple Kappa example"
},
{
"Version": "12",
"CodeSha256": "JklpzNjuO6TLDiNe6nVYWeo1Imq6bF5uaMt2L0bqp5Y=",
"FunctionName": "kappa-simple",
"MemorySize": 256,
"CodeSize": 948,
"FunctionArn": "arn:aws:lambda:us-west-2:123456789012:function:kappa-simple:12",
"Handler": "simple.handler",
"Role": "arn:aws:iam::123456789012:role/kappa/kappa-simple_dev",
"Timeout": 3,
"LastModified": "2015-12-14T04:13:56.737+0000",
"Runtime": "python2.7",
"Description": "A very simple Kappa example"
}
]
}
}
# Copyright (c) 2015 Mitch Garnaat http://garnaat.org/
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file 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 unittest
import os
import shutil
import mock
import placebo
import kappa.context
import kappa.awsclient
class TestLog(unittest.TestCase):
def setUp(self):
self.environ = {}
self.environ_patch = mock.patch('os.environ', self.environ)
self.environ_patch.start()
credential_path = os.path.join(os.path.dirname(__file__), 'cfg',
'aws_credentials')
self.environ['AWS_SHARED_CREDENTIALS_FILE'] = credential_path
self.prj_path = os.path.join(os.path.dirname(__file__), 'foobar')
cache_file = os.path.join(self.prj_path, '.kappa')
if os.path.exists(cache_file):
shutil.rmtree(cache_file)
self.data_path = os.path.join(os.path.dirname(__file__), 'responses')
self.data_path = os.path.join(self.data_path, 'deploy')
self.session = kappa.awsclient.create_session('foobar', 'us-west-2')
def tearDown(self):
pass
def test_deploy(self):
pill = placebo.attach(self.session, self.data_path)
pill.playback()
os.chdir(self.prj_path)
cfg_filepath = os.path.join(self.prj_path, 'kappa.yml')
cfg_fp = open(cfg_filepath)
ctx = kappa.context.Context(cfg_fp, 'dev')
ctx.deploy()
ctx.deploy()
# Copyright (c) 2014 Mitch Garnaat http://garnaat.org/
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file 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 unittest
import mock
from kappa.log import Log
from tests.unit.mock_aws import get_aws
class TestLog(unittest.TestCase):
def setUp(self):
self.aws_patch = mock.patch('kappa.aws.get_aws', get_aws)
self.mock_aws = self.aws_patch.start()
def tearDown(self):
self.aws_patch.stop()
def test_streams(self):
mock_context = mock.Mock()
log = Log(mock_context, 'foo/bar')
streams = log.streams()
self.assertEqual(len(streams), 6)
def test_tail(self):
mock_context = mock.Mock()
log = Log(mock_context, 'foo/bar')
events = log.tail()
self.assertEqual(len(events), 6)
self.assertEqual(events[0]['ingestionTime'], 1420569036909)
self.assertIn('RequestId: 23007242-95d2-11e4-a10e-7b2ab60a7770',
events[-1]['message'])
# Copyright (c) 2015 Mitch Garnaat http://garnaat.org/
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file 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 unittest
import os
import mock
from kappa.policy import Policy
from tests.unit.mock_aws import get_aws
Config1 = {
'name': 'FooPolicy',
'description': 'This is the Foo policy',
'document': 'FooPolicy.json'}
Config2 = {
'name': 'BazPolicy',
'description': 'This is the Baz policy',
'document': 'BazPolicy.json'}
def path(filename):
return os.path.join(os.path.dirname(__file__), 'data', filename)
class TestPolicy(unittest.TestCase):
def setUp(self):
self.aws_patch = mock.patch('kappa.aws.get_aws', get_aws)
self.mock_aws = self.aws_patch.start()
Config1['document'] = path(Config1['document'])
Config2['document'] = path(Config2['document'])
def tearDown(self):
self.aws_patch.stop()
def test_properties(self):
mock_context = mock.Mock()
policy = Policy(mock_context, Config1)
self.assertEqual(policy.name, Config1['name'])
self.assertEqual(policy.document, Config1['document'])
self.assertEqual(policy.description, Config1['description'])
def test_exists(self):
mock_context = mock.Mock()
policy = Policy(mock_context, Config1)
self.assertTrue(policy.exists())
def test_not_exists(self):
mock_context = mock.Mock()
policy = Policy(mock_context, Config2)
self.assertFalse(policy.exists())
def test_create(self):
mock_context = mock.Mock()
policy = Policy(mock_context, Config2)
policy.create()
def test_delete(self):
mock_context = mock.Mock()
policy = Policy(mock_context, Config1)
policy.delete()
# Copyright (c) 2015 Mitch Garnaat http://garnaat.org/
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file 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 unittest
import mock
from kappa.role import Role
from tests.unit.mock_aws import get_aws
Config1 = {'name': 'FooRole'}
Config2 = {'name': 'BazRole'}
class TestRole(unittest.TestCase):
def setUp(self):
self.aws_patch = mock.patch('kappa.aws.get_aws', get_aws)
self.mock_aws = self.aws_patch.start()
def tearDown(self):
self.aws_patch.stop()
def test_properties(self):
mock_context = mock.Mock()
role = Role(mock_context, Config1)
self.assertEqual(role.name, Config1['name'])
def test_exists(self):
mock_context = mock.Mock()
role = Role(mock_context, Config1)
self.assertTrue(role.exists())
def test_not_exists(self):
mock_context = mock.Mock()
role = Role(mock_context, Config2)
self.assertFalse(role.exists())
def test_create(self):
mock_context = mock.Mock()
role = Role(mock_context, Config2)
role.create()
def test_delete(self):
mock_context = mock.Mock()
role = Role(mock_context, Config1)
role.delete()