mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
2335 lines
85 KiB
Python
2335 lines
85 KiB
Python
import datetime
|
|
import logging
|
|
import os
|
|
import random
|
|
import string
|
|
|
|
import pytest
|
|
|
|
import salt.config
|
|
import salt.loader
|
|
import salt.states.boto_apigateway as boto_apigateway
|
|
import salt.utils.files
|
|
import salt.utils.yaml
|
|
from salt.utils.versions import Version
|
|
from tests.support.mixins import LoaderModuleMockMixin
|
|
from tests.support.mock import MagicMock, patch
|
|
from tests.support.unit import TestCase
|
|
|
|
# pylint: disable=import-error,no-name-in-module
|
|
from tests.unit.modules.test_boto_apigateway import BotoApiGatewayTestCaseMixin
|
|
|
|
try:
|
|
import boto3
|
|
import botocore
|
|
from botocore.exceptions import ClientError
|
|
|
|
HAS_BOTO = True
|
|
except ImportError:
|
|
HAS_BOTO = False
|
|
|
|
pytestmark = [
|
|
pytest.mark.skip_on_fips_enabled_platform,
|
|
]
|
|
|
|
|
|
# pylint: enable=import-error,no-name-in-module
|
|
|
|
# the boto_apigateway module relies on the connect_to_region() method
|
|
# which was added in boto 2.8.0
|
|
# https://github.com/boto/boto/commit/33ac26b416fbb48a60602542b4ce15dcc7029f12
|
|
required_boto3_version = "1.2.1"
|
|
required_botocore_version = "1.4.49"
|
|
|
|
region = "us-east-1"
|
|
access_key = "GKTADJGHEIQSXMKKRBJ08H"
|
|
secret_key = "askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs"
|
|
conn_parameters = {
|
|
"region": region,
|
|
"key": access_key,
|
|
"keyid": secret_key,
|
|
"profile": {},
|
|
}
|
|
error_message = (
|
|
"An error occurred (101) when calling the {0} operation: Test-defined error"
|
|
)
|
|
error_content = {"Error": {"Code": 101, "Message": "Test-defined error"}}
|
|
|
|
api_ret = dict(
|
|
description=(
|
|
'{\n "context": "See deployment or stage description",\n '
|
|
' "provisioned_by": "Salt boto_apigateway.present State"\n}'
|
|
),
|
|
createdDate=datetime.datetime(2015, 11, 17, 16, 33, 50),
|
|
id="vni0vq8wzi",
|
|
name="unit test api",
|
|
)
|
|
|
|
no_apis_ret = {"items": []}
|
|
|
|
apis_ret = {"items": [api_ret]}
|
|
|
|
mock_model_ret = dict(
|
|
contentType="application/json",
|
|
description="mock model",
|
|
id="123abc",
|
|
name="mock model",
|
|
schema=(
|
|
"{\n"
|
|
' "$schema": "http://json-schema.org/draft-04/schema#",\n'
|
|
' "properties": {\n'
|
|
' "field": {\n'
|
|
' "type": "string"\n'
|
|
" }\n"
|
|
" }\n"
|
|
"}"
|
|
),
|
|
)
|
|
|
|
models_ret = {
|
|
"items": [
|
|
dict(
|
|
contentType="application/json",
|
|
description="Error",
|
|
id="50nw8r",
|
|
name="Error",
|
|
schema=(
|
|
"{\n"
|
|
' "$schema": "http://json-schema.org/draft-04/schema#",\n'
|
|
' "properties": {\n'
|
|
' "code": {\n'
|
|
' "format": "int32",\n'
|
|
' "type": "integer"\n'
|
|
" },\n"
|
|
' "fields": {\n'
|
|
' "type": "string"\n'
|
|
" },\n"
|
|
' "message": {\n'
|
|
' "type": "string"\n'
|
|
" }\n"
|
|
" },\n"
|
|
' "title": "Error Schema",\n'
|
|
' "type": "object"\n'
|
|
"}"
|
|
),
|
|
),
|
|
dict(
|
|
contentType="application/json",
|
|
description="User",
|
|
id="terlnw",
|
|
name="User",
|
|
schema=(
|
|
"{\n"
|
|
' "$schema": "http://json-schema.org/draft-04/schema#",\n'
|
|
' "properties": {\n'
|
|
' "password": {\n'
|
|
' "description": "A password for the new user",\n'
|
|
' "type": "string"\n'
|
|
" },\n"
|
|
' "username": {\n'
|
|
' "description": "A unique username for the user",\n'
|
|
' "type": "string"\n'
|
|
" }\n"
|
|
" },\n"
|
|
' "title": "User Schema",\n'
|
|
' "type": "object"\n'
|
|
"}"
|
|
),
|
|
),
|
|
]
|
|
}
|
|
|
|
root_resources_ret = {"items": [dict(id="bgk0rk8rqb", path="/")]}
|
|
|
|
resources_ret = {
|
|
"items": [
|
|
dict(id="bgk0rk8rqb", path="/"),
|
|
dict(
|
|
id="9waiaz",
|
|
parentId="bgk0rk8rqb",
|
|
path="/users",
|
|
pathPart="users",
|
|
resourceMethods={"POST": {}},
|
|
),
|
|
]
|
|
}
|
|
|
|
no_resources_ret = {"items": []}
|
|
|
|
stage1_deployment1_ret = dict(
|
|
cacheClusterEnabled=False,
|
|
cacheClusterSize=0.5,
|
|
cacheClusterStatus="NOT_AVAILABLE",
|
|
createdDate=datetime.datetime(2015, 11, 17, 16, 33, 50),
|
|
deploymentId="kobnrb",
|
|
description=(
|
|
"{\n"
|
|
' "current_deployment_label": {\n'
|
|
' "api_name": "unit test api",\n'
|
|
' "swagger_file": "temp-swagger-sample.yaml",\n'
|
|
' "swagger_file_md5sum": "4fb17e43bab3a96e7f2410a1597cd0a5",\n'
|
|
' "swagger_info_object": {\n'
|
|
' "description": "salt boto apigateway unit test service",\n'
|
|
' "title": "salt boto apigateway unit test service",\n'
|
|
' "version": "0.0.0"\n'
|
|
" }\n"
|
|
" }\n"
|
|
"}"
|
|
),
|
|
lastUpdatedDate=datetime.datetime(2015, 11, 17, 16, 33, 50),
|
|
methodSettings=dict(),
|
|
stageName="test",
|
|
variables=dict(),
|
|
)
|
|
|
|
stage1_deployment1_vars_ret = dict(
|
|
cacheClusterEnabled=False,
|
|
cacheClusterSize=0.5,
|
|
cacheClusterStatus="NOT_AVAILABLE",
|
|
createdDate=datetime.datetime(2015, 11, 17, 16, 33, 50),
|
|
deploymentId="kobnrb",
|
|
description=(
|
|
"{\n"
|
|
' "current_deployment_label": {\n'
|
|
' "api_name": "unit test api",\n'
|
|
' "swagger_file": "temp-swagger-sample.yaml",\n'
|
|
' "swagger_file_md5sum": "4fb17e43bab3a96e7f2410a1597cd0a5",\n'
|
|
' "swagger_info_object": {\n'
|
|
' "description": "salt boto apigateway unit test service",\n'
|
|
' "title": "salt boto apigateway unit test service",\n'
|
|
' "version": "0.0.0"\n'
|
|
" }\n"
|
|
" }\n"
|
|
"}"
|
|
),
|
|
lastUpdatedDate=datetime.datetime(2015, 11, 17, 16, 33, 50),
|
|
methodSettings=dict(),
|
|
stageName="test",
|
|
variables={"var1": "val1"},
|
|
)
|
|
|
|
stage1_deployment2_ret = dict(
|
|
cacheClusterEnabled=False,
|
|
cacheClusterSize=0.5,
|
|
cacheClusterStatus="NOT_AVAILABLE",
|
|
createdDate=datetime.datetime(2015, 11, 17, 16, 33, 50),
|
|
deploymentId="kobnrc",
|
|
description=(
|
|
"{\n"
|
|
' "current_deployment_label": {\n'
|
|
' "api_name": "unit test api",\n'
|
|
' "swagger_file": "temp-swagger-sample.yaml",\n'
|
|
' "swagger_file_md5sum": "5fd538c4336ed5c54b4bf39ddf97c661",\n'
|
|
' "swagger_info_object": {\n'
|
|
' "description": "salt boto apigateway unit test service",\n'
|
|
' "title": "salt boto apigateway unit test service",\n'
|
|
' "version": "0.0.2"\n'
|
|
" }\n"
|
|
" }\n"
|
|
"}"
|
|
),
|
|
lastUpdatedDate=datetime.datetime(2015, 11, 17, 16, 33, 50),
|
|
methodSettings=dict(),
|
|
stageName="test",
|
|
variables=dict(),
|
|
)
|
|
|
|
stage2_ret = dict(
|
|
cacheClusterEnabled=False,
|
|
cacheClusterSize=0.5,
|
|
cacheClusterStatus="NOT_AVAILABLE",
|
|
createdDate=datetime.datetime(2015, 11, 17, 16, 33, 50),
|
|
deploymentId="kobnrb",
|
|
description=(
|
|
"{\n"
|
|
' "current_deployment_label": {\n'
|
|
' "api_name": "unit test api",\n'
|
|
' "swagger_file": "temp-swagger-sample.yaml",\n'
|
|
' "swagger_file_md5sum": "4fb17e43bab3a96e7f2410a1597cd0a5",\n'
|
|
' "swagger_info_object": {\n'
|
|
' "description": "salt boto apigateway unit test service",\n'
|
|
' "title": "salt boto apigateway unit test service",\n'
|
|
' "version": "0.0.0"\n'
|
|
" }\n"
|
|
" }\n"
|
|
"}"
|
|
),
|
|
lastUpdatedDate=datetime.datetime(2015, 11, 17, 16, 33, 50),
|
|
methodSettings=dict(),
|
|
stageName="dev",
|
|
variables=dict(),
|
|
)
|
|
|
|
stages_stage2_ret = {"item": [stage2_ret]}
|
|
|
|
no_stages_ret = {"item": []}
|
|
|
|
deployment1_ret = dict(
|
|
createdDate=datetime.datetime(2015, 11, 17, 16, 33, 50),
|
|
description=(
|
|
"{\n"
|
|
' "api_name": "unit test api",\n'
|
|
' "swagger_file": "temp-swagger-sample.yaml",\n'
|
|
' "swagger_file_md5sum": "55a948ff90ad80ff747ec91657c7a299",\n'
|
|
' "swagger_info_object": {\n'
|
|
' "description": "salt boto apigateway unit test service",\n'
|
|
' "title": "salt boto apigateway unit test service",\n'
|
|
' "version": "0.0.0"\n'
|
|
" }\n"
|
|
"}"
|
|
),
|
|
id="kobnrb",
|
|
)
|
|
|
|
deployment2_ret = dict(
|
|
createdDate=datetime.datetime(2015, 11, 17, 16, 33, 50),
|
|
description=(
|
|
"{\n"
|
|
' "api_name": "unit test api",\n'
|
|
' "swagger_file": "temp-swagger-sample.yaml",\n'
|
|
' "swagger_file_md5sum": "5fd538c4336ed5c54b4bf39ddf97c661",\n'
|
|
' "swagger_info_object": {\n'
|
|
' "description": "salt boto apigateway unit test service",\n'
|
|
' "title": "salt boto apigateway unit test service",\n'
|
|
' "version": "0.0.2"\n'
|
|
" }\n"
|
|
"}"
|
|
),
|
|
id="kobnrc",
|
|
)
|
|
|
|
deployments_ret = {"items": [deployment1_ret, deployment2_ret]}
|
|
|
|
function_ret = dict(
|
|
FunctionName="unit_test_api_users_post",
|
|
Runtime="python2.7",
|
|
Role=None,
|
|
Handler="handler",
|
|
Description="abcdefg",
|
|
Timeout=5,
|
|
MemorySize=128,
|
|
CodeSha256="abcdef",
|
|
CodeSize=199,
|
|
FunctionArn="arn:lambda:us-east-1:1234:Something",
|
|
LastModified="yes",
|
|
)
|
|
|
|
method_integration_response_200_ret = dict(
|
|
responseParameters={"method.response.header.Access-Control-Allow-Origin": "*"},
|
|
responseTemplates={},
|
|
selectionPattern=".*",
|
|
statusCode="200",
|
|
)
|
|
|
|
method_integration_ret = dict(
|
|
cacheKeyParameters={},
|
|
cacheNamespace="9waiaz",
|
|
credentials="arn:aws:iam::1234:role/apigatewayrole",
|
|
httpMethod="POST",
|
|
integrationResponses={"200": method_integration_response_200_ret},
|
|
requestParameters={},
|
|
requestTemplates={
|
|
"application/json": (
|
|
"#set($inputRoot = $input.path('$')){\"header-params\" : {#set ($map ="
|
|
' $input.params().header)#foreach( $param in $map.entrySet() )"$param.key"'
|
|
' : "$param.value" #if( $foreach.hasNext ), #end#end},"query-params" :'
|
|
" {#set ($map = $input.params().querystring)#foreach( $param in"
|
|
' $map.entrySet() )"$param.key" : "$param.value" #if( $foreach.hasNext ),'
|
|
' #end#end},"path-params" : {#set ($map = $input.params().path)#foreach('
|
|
' $param in $map.entrySet() )"$param.key" : "$param.value" #if('
|
|
" $foreach.hasNext ), #end#end},\"body-params\" : $input.json('$')}"
|
|
)
|
|
},
|
|
type="AWS",
|
|
uri=(
|
|
"arn:aws:apigateway:us-west-2:"
|
|
"lambda:path/2015-03-31/functions/arn:aws:lambda:us-west-2:1234567:"
|
|
"function:unit_test_api_api_users_post/invocations"
|
|
),
|
|
)
|
|
|
|
method_response_200_ret = dict(
|
|
responseModels={"application/json": "User"},
|
|
responseParameters={"method.response.header.Access-Control-Allow-Origin": False},
|
|
statusCode="200",
|
|
)
|
|
|
|
method_ret = dict(
|
|
apiKeyRequired=False,
|
|
authorizationType="None",
|
|
httpMethod="POST",
|
|
methodIntegration=method_integration_ret,
|
|
methodResponses={"200": method_response_200_ret},
|
|
requestModels={"application/json": "User"},
|
|
requestParameters={},
|
|
)
|
|
|
|
throttle_rateLimit = 10.0
|
|
association_stage_1 = {"apiId": "apiId1", "stage": "stage1"}
|
|
association_stage_2 = {"apiId": "apiId1", "stage": "stage2"}
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
def _has_required_boto():
|
|
"""
|
|
Returns True/False boolean depending on if Boto is installed and correct
|
|
version.
|
|
"""
|
|
if not HAS_BOTO:
|
|
return False
|
|
elif Version(boto3.__version__) < Version(required_boto3_version):
|
|
return False
|
|
else:
|
|
return True
|
|
|
|
|
|
def _has_required_botocore():
|
|
"""
|
|
Returns True/False boolean depending on if botocore supports usage plan
|
|
"""
|
|
if not HAS_BOTO:
|
|
return False
|
|
elif Version(botocore.__version__) < Version(required_botocore_version):
|
|
return False
|
|
else:
|
|
return True
|
|
|
|
|
|
class TempSwaggerFile:
|
|
_tmp_swagger_dict = {
|
|
"info": {
|
|
"version": "0.0.0",
|
|
"description": "salt boto apigateway unit test service",
|
|
"title": "salt boto apigateway unit test service",
|
|
},
|
|
"paths": {
|
|
"/users": {
|
|
"post": {
|
|
"responses": {
|
|
"200": {
|
|
"headers": {
|
|
"Access-Control-Allow-Origin": {"type": "string"}
|
|
},
|
|
"description": "The username of the new user",
|
|
"schema": {"$ref": "#/definitions/User"},
|
|
}
|
|
},
|
|
"parameters": [
|
|
{
|
|
"in": "body",
|
|
"description": "New user details.",
|
|
"name": "NewUser",
|
|
"schema": {"$ref": "#/definitions/User"},
|
|
}
|
|
],
|
|
"produces": ["application/json"],
|
|
"description": "Creates a new user.",
|
|
"tags": ["Auth"],
|
|
"consumes": ["application/json"],
|
|
"summary": "Registers a new user",
|
|
}
|
|
}
|
|
},
|
|
"schemes": ["https"],
|
|
"produces": ["application/json"],
|
|
"basePath": "/api",
|
|
"host": "rm06h9oac4.execute-api.us-west-2.amazonaws.com",
|
|
"definitions": {
|
|
"User": {
|
|
"properties": {
|
|
"username": {
|
|
"type": "string",
|
|
"description": "A unique username for the user",
|
|
},
|
|
"password": {
|
|
"type": "string",
|
|
"description": "A password for the new user",
|
|
},
|
|
}
|
|
},
|
|
"Error": {
|
|
"properties": {
|
|
"fields": {"type": "string"},
|
|
"message": {"type": "string"},
|
|
"code": {"type": "integer", "format": "int32"},
|
|
}
|
|
},
|
|
},
|
|
"swagger": "2.0",
|
|
}
|
|
|
|
def __enter__(self):
|
|
self.swaggerfile = "temp-swagger-sample.yaml"
|
|
with salt.utils.files.fopen(self.swaggerfile, "w") as fp_:
|
|
salt.utils.yaml.safe_dump(self.swaggerdict, fp_, default_flow_style=False)
|
|
return self.swaggerfile
|
|
|
|
def __exit__(self, objtype, value, traceback):
|
|
os.remove(self.swaggerfile)
|
|
|
|
def __init__(self, create_invalid_file=False):
|
|
if create_invalid_file:
|
|
self.swaggerdict = TempSwaggerFile._tmp_swagger_dict.copy()
|
|
# add an invalid top level key
|
|
self.swaggerdict["invalid_key"] = "invalid"
|
|
# remove one of the required keys 'schemes'
|
|
self.swaggerdict.pop("schemes", None)
|
|
# set swagger version to an unsupported version 3.0
|
|
self.swaggerdict["swagger"] = "3.0"
|
|
# missing info object
|
|
self.swaggerdict.pop("info", None)
|
|
else:
|
|
self.swaggerdict = TempSwaggerFile._tmp_swagger_dict
|
|
|
|
|
|
class BotoApiGatewayStateTestCaseBase(TestCase, LoaderModuleMockMixin):
|
|
conn = None
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
cls.opts = salt.config.DEFAULT_MINION_OPTS.copy()
|
|
cls.opts["grains"] = salt.loader.grains(cls.opts)
|
|
|
|
@classmethod
|
|
def tearDownClass(cls):
|
|
del cls.opts
|
|
|
|
def setup_loader_modules(self):
|
|
context = {}
|
|
utils = salt.loader.utils(
|
|
self.opts,
|
|
whitelist=["boto", "boto3", "args", "systemd", "path", "platform", "reg"],
|
|
context=context,
|
|
)
|
|
serializers = salt.loader.serializers(self.opts)
|
|
self.funcs = salt.loader.minion_mods(
|
|
self.opts, context=context, utils=utils, whitelist=["boto_apigateway"]
|
|
)
|
|
self.salt_states = salt.loader.states(
|
|
opts=self.opts,
|
|
functions=self.funcs,
|
|
utils=utils,
|
|
whitelist=["boto_apigateway"],
|
|
serializers=serializers,
|
|
)
|
|
return {
|
|
boto_apigateway: {
|
|
"__opts__": self.opts,
|
|
"__utils__": utils,
|
|
"__salt__": self.funcs,
|
|
"__states__": self.salt_states,
|
|
"__serializers__": serializers,
|
|
}
|
|
}
|
|
|
|
# Set up MagicMock to replace the boto3 session
|
|
def setUp(self):
|
|
self.addCleanup(delattr, self, "funcs")
|
|
self.addCleanup(delattr, self, "salt_states")
|
|
# connections keep getting cached from prior tests, can't find the
|
|
# correct context object to clear it. So randomize the cache key, to prevent any
|
|
# cache hits
|
|
conn_parameters["key"] = "".join(
|
|
random.choice(string.ascii_lowercase + string.digits) for _ in range(50)
|
|
)
|
|
|
|
patcher = patch("boto3.session.Session")
|
|
self.addCleanup(patcher.stop)
|
|
mock_session = patcher.start()
|
|
|
|
session_instance = mock_session.return_value
|
|
self.conn = MagicMock()
|
|
self.addCleanup(delattr, self, "conn")
|
|
session_instance.client.return_value = self.conn
|
|
|
|
|
|
@pytest.mark.skipif(HAS_BOTO is False, reason="The boto module must be installed.")
|
|
@pytest.mark.skipif(
|
|
_has_required_boto() is False,
|
|
reason="The boto3 module must be greater than or equal to version {}".format(
|
|
required_boto3_version
|
|
),
|
|
)
|
|
class BotoApiGatewayTestCase(
|
|
BotoApiGatewayStateTestCaseBase, BotoApiGatewayTestCaseMixin
|
|
):
|
|
"""
|
|
TestCase for salt.modules.boto_apigateway state.module
|
|
"""
|
|
|
|
def test_present_when_swagger_file_is_invalid(self):
|
|
"""
|
|
Tests present when the swagger file is invalid.
|
|
"""
|
|
result = {}
|
|
with TempSwaggerFile(create_invalid_file=True) as swagger_file:
|
|
result = self.salt_states["boto_apigateway.present"](
|
|
"api present",
|
|
"unit test api",
|
|
swagger_file,
|
|
"test",
|
|
False,
|
|
"arn:aws:iam::1234:role/apigatewayrole",
|
|
**conn_parameters
|
|
)
|
|
|
|
self.assertFalse(result.get("result", True))
|
|
|
|
def test_present_when_stage_is_already_at_desired_deployment(self):
|
|
"""
|
|
Tests scenario where no action will be taken since we're already
|
|
at desired state
|
|
"""
|
|
self.conn.get_rest_apis.return_value = apis_ret
|
|
self.conn.get_deployment.return_value = deployment1_ret
|
|
self.conn.get_stage.return_value = stage1_deployment1_ret
|
|
self.conn.update_stage.side_effect = ClientError(
|
|
error_content, "update_stage should not be called"
|
|
)
|
|
result = {}
|
|
with TempSwaggerFile() as swagger_file:
|
|
result = self.salt_states["boto_apigateway.present"](
|
|
"api present",
|
|
"unit test api",
|
|
swagger_file,
|
|
"test",
|
|
False,
|
|
"arn:aws:iam::1234:role/apigatewayrole",
|
|
**conn_parameters
|
|
)
|
|
self.assertFalse(result.get("abort"))
|
|
self.assertTrue(result.get("current"))
|
|
self.assertIs(result.get("result"), True)
|
|
self.assertNotIn("update_stage should not be called", result.get("comment", ""))
|
|
|
|
def test_present_when_stage_is_already_at_desired_deployment_and_needs_stage_variables_update(
|
|
self,
|
|
):
|
|
"""
|
|
Tests scenario where the deployment is current except for the need to update stage variables
|
|
from {} to {'var1':'val1'}
|
|
"""
|
|
self.conn.get_rest_apis.return_value = apis_ret
|
|
self.conn.get_deployment.return_value = deployment1_ret
|
|
self.conn.get_stage.return_value = stage1_deployment1_ret
|
|
self.conn.update_stage.return_value = stage1_deployment1_vars_ret
|
|
result = {}
|
|
with TempSwaggerFile() as swagger_file:
|
|
result = self.salt_states["boto_apigateway.present"](
|
|
"api present",
|
|
"unit test api",
|
|
swagger_file,
|
|
"test",
|
|
False,
|
|
"arn:aws:iam::1234:role/apigatewayrole",
|
|
stage_variables={"var1": "val1"},
|
|
**conn_parameters
|
|
)
|
|
|
|
self.assertFalse(result.get("abort"))
|
|
self.assertTrue(result.get("current"))
|
|
self.assertIs(result.get("result"), True)
|
|
|
|
def test_present_when_stage_exists_and_is_to_associate_to_existing_deployment(self):
|
|
"""
|
|
Tests scenario where we merely reassociate a stage to a pre-existing
|
|
deployments
|
|
"""
|
|
self.conn.get_rest_apis.return_value = apis_ret
|
|
self.conn.get_deployment.return_value = deployment2_ret
|
|
self.conn.get_deployments.return_value = deployments_ret
|
|
self.conn.get_stage.return_value = stage1_deployment2_ret
|
|
self.conn.update_stage.return_value = stage1_deployment1_ret
|
|
|
|
# should never get to the following calls
|
|
self.conn.create_stage.side_effect = ClientError(error_content, "create_stage")
|
|
self.conn.create_deployment.side_effect = ClientError(
|
|
error_content, "create_deployment"
|
|
)
|
|
|
|
result = {}
|
|
with TempSwaggerFile() as swagger_file:
|
|
result = self.salt_states["boto_apigateway.present"](
|
|
"api present",
|
|
"unit test api",
|
|
swagger_file,
|
|
"test",
|
|
False,
|
|
"arn:aws:iam::1234:role/apigatewayrole",
|
|
**conn_parameters
|
|
)
|
|
|
|
self.assertTrue(result.get("publish"))
|
|
self.assertIs(result.get("result"), True)
|
|
self.assertFalse(result.get("abort"))
|
|
self.assertTrue(result.get("changes", {}).get("new", [{}])[0])
|
|
|
|
@pytest.mark.slow_test
|
|
def test_present_when_stage_is_to_associate_to_new_deployment(self):
|
|
"""
|
|
Tests creation of a new api/model/resource given nothing has been created previously
|
|
"""
|
|
# no api existed
|
|
self.conn.get_rest_apis.return_value = no_apis_ret
|
|
# create top level api
|
|
self.conn.create_rest_api.return_value = api_ret
|
|
# no models existed in the newly created api
|
|
self.conn.get_model.side_effect = ClientError(error_content, "get_model")
|
|
# create model return values
|
|
self.conn.create_model.return_value = mock_model_ret
|
|
# various paths/resources already created
|
|
self.conn.get_resources.return_value = resources_ret
|
|
# the following should never be called
|
|
self.conn.create_resource.side_effect = ClientError(
|
|
error_content, "create_resource"
|
|
)
|
|
|
|
# create api method for POST
|
|
self.conn.put_method.return_value = method_ret
|
|
# create api method integration for POST
|
|
self.conn.put_integration.return_value = method_integration_ret
|
|
# create api method response for POST/200
|
|
self.conn.put_method_response.return_value = method_response_200_ret
|
|
# create api method integration response for POST
|
|
self.conn.put_intgration_response.return_value = (
|
|
method_integration_response_200_ret
|
|
)
|
|
|
|
result = {}
|
|
with patch.dict(
|
|
self.funcs,
|
|
{
|
|
"boto_lambda.describe_function": MagicMock(
|
|
return_value={"function": function_ret}
|
|
)
|
|
},
|
|
):
|
|
with TempSwaggerFile() as swagger_file:
|
|
result = self.salt_states["boto_apigateway.present"](
|
|
"api present",
|
|
"unit test api",
|
|
swagger_file,
|
|
"test",
|
|
False,
|
|
"arn:aws:iam::1234:role/apigatewayrole",
|
|
**conn_parameters
|
|
)
|
|
|
|
self.assertIs(result.get("result"), True)
|
|
self.assertIs(result.get("abort"), None)
|
|
|
|
def test_present_when_stage_associating_to_new_deployment_errored_on_api_creation(
|
|
self,
|
|
):
|
|
"""
|
|
Tests creation of a new api/model/resource given nothing has been created previously,
|
|
and we failed on creating the top level api object.
|
|
"""
|
|
# no api existed
|
|
self.conn.get_rest_apis.return_value = no_apis_ret
|
|
# create top level api
|
|
self.conn.create_rest_api.side_effect = ClientError(
|
|
error_content, "create_rest_api"
|
|
)
|
|
|
|
result = {}
|
|
with TempSwaggerFile() as swagger_file:
|
|
result = self.salt_states["boto_apigateway.present"](
|
|
"api present",
|
|
"unit test api",
|
|
swagger_file,
|
|
"test",
|
|
False,
|
|
"arn:aws:iam::1234:role/apigatewayrole",
|
|
**conn_parameters
|
|
)
|
|
|
|
self.assertIs(result.get("abort"), True)
|
|
self.assertIs(result.get("result"), False)
|
|
self.assertIn("create_rest_api", result.get("comment", ""))
|
|
|
|
def test_present_when_stage_associating_to_new_deployment_errored_on_model_creation(
|
|
self,
|
|
):
|
|
"""
|
|
Tests creation of a new api/model/resource given nothing has been created previously,
|
|
and we failed on creating the models after successful creation of top level api object.
|
|
"""
|
|
# no api existed
|
|
self.conn.get_rest_apis.return_value = no_apis_ret
|
|
# create top level api
|
|
self.conn.create_rest_api.return_value = api_ret
|
|
# no models existed in the newly created api
|
|
self.conn.get_model.side_effect = ClientError(error_content, "get_model")
|
|
# create model return error
|
|
self.conn.create_model.side_effect = ClientError(error_content, "create_model")
|
|
|
|
result = {}
|
|
with TempSwaggerFile() as swagger_file:
|
|
result = self.salt_states["boto_apigateway.present"](
|
|
"api present",
|
|
"unit test api",
|
|
swagger_file,
|
|
"test",
|
|
False,
|
|
"arn:aws:iam::1234:role/apigatewayrole",
|
|
**conn_parameters
|
|
)
|
|
|
|
self.assertIs(result.get("abort"), True)
|
|
self.assertIs(result.get("result"), False)
|
|
self.assertIn("create_model", result.get("comment", ""))
|
|
|
|
def test_present_when_stage_associating_to_new_deployment_errored_on_resource_creation(
|
|
self,
|
|
):
|
|
"""
|
|
Tests creation of a new api/model/resource given nothing has been created previously,
|
|
and we failed on creating the resource (paths) after successful creation of top level api/model
|
|
objects.
|
|
"""
|
|
# no api existed
|
|
self.conn.get_rest_apis.return_value = no_apis_ret
|
|
# create top level api
|
|
self.conn.create_rest_api.return_value = api_ret
|
|
# no models existed in the newly created api
|
|
self.conn.get_model.side_effect = ClientError(error_content, "get_model")
|
|
# create model return values
|
|
self.conn.create_model.return_value = mock_model_ret
|
|
# get resources has nothing intiially except to the root path '/'
|
|
self.conn.get_resources.return_value = root_resources_ret
|
|
# create resources return error
|
|
self.conn.create_resource.side_effect = ClientError(
|
|
error_content, "create_resource"
|
|
)
|
|
result = {}
|
|
with TempSwaggerFile() as swagger_file:
|
|
result = self.salt_states["boto_apigateway.present"](
|
|
"api present",
|
|
"unit test api",
|
|
swagger_file,
|
|
"test",
|
|
False,
|
|
"arn:aws:iam::1234:role/apigatewayrole",
|
|
**conn_parameters
|
|
)
|
|
self.assertIs(result.get("abort"), True)
|
|
self.assertIs(result.get("result"), False)
|
|
self.assertIn("create_resource", result.get("comment", ""))
|
|
|
|
@pytest.mark.slow_test
|
|
def test_present_when_stage_associating_to_new_deployment_errored_on_put_method(
|
|
self,
|
|
):
|
|
"""
|
|
Tests creation of a new api/model/resource given nothing has been created previously,
|
|
and we failed on adding a post method to the resource after successful creation of top level
|
|
api, model, resource objects.
|
|
"""
|
|
# no api existed
|
|
self.conn.get_rest_apis.return_value = no_apis_ret
|
|
# create top level api
|
|
self.conn.create_rest_api.return_value = api_ret
|
|
# no models existed in the newly created api
|
|
self.conn.get_model.side_effect = ClientError(error_content, "get_model")
|
|
# create model return values
|
|
self.conn.create_model.return_value = mock_model_ret
|
|
# various paths/resources already created
|
|
self.conn.get_resources.return_value = resources_ret
|
|
# the following should never be called
|
|
self.conn.create_resource.side_effect = ClientError(
|
|
error_content, "create_resource"
|
|
)
|
|
|
|
# create api method for POST
|
|
self.conn.put_method.side_effect = ClientError(error_content, "put_method")
|
|
|
|
result = {}
|
|
with patch.dict(
|
|
self.funcs,
|
|
{
|
|
"boto_lambda.describe_function": MagicMock(
|
|
return_value={"function": function_ret}
|
|
)
|
|
},
|
|
):
|
|
with TempSwaggerFile() as swagger_file:
|
|
result = self.salt_states["boto_apigateway.present"](
|
|
"api present",
|
|
"unit test api",
|
|
swagger_file,
|
|
"test",
|
|
False,
|
|
"arn:aws:iam::1234:role/apigatewayrole",
|
|
**conn_parameters
|
|
)
|
|
|
|
self.assertIs(result.get("abort"), True)
|
|
self.assertIs(result.get("result"), False)
|
|
self.assertIn("put_method", result.get("comment", ""))
|
|
|
|
@pytest.mark.slow_test
|
|
def test_present_when_stage_associating_to_new_deployment_errored_on_lambda_function_lookup(
|
|
self,
|
|
):
|
|
"""
|
|
Tests creation of a new api/model/resource given nothing has been created previously,
|
|
and we failed on adding a post method due to a lamda look up failure after successful
|
|
creation of top level api, model, resource objects.
|
|
"""
|
|
# no api existed
|
|
self.conn.get_rest_apis.return_value = no_apis_ret
|
|
# create top level api
|
|
self.conn.create_rest_api.return_value = api_ret
|
|
# no models existed in the newly created api
|
|
self.conn.get_model.side_effect = ClientError(error_content, "get_model")
|
|
# create model return values
|
|
self.conn.create_model.return_value = mock_model_ret
|
|
# various paths/resources already created
|
|
self.conn.get_resources.return_value = resources_ret
|
|
# the following should never be called
|
|
self.conn.create_resource.side_effect = ClientError(
|
|
error_content, "create_resource"
|
|
)
|
|
# create api method for POST
|
|
self.conn.put_method.return_value = method_ret
|
|
# create api method integration for POST
|
|
self.conn.put_integration.side_effect = ClientError(
|
|
error_content, "put_integration should not be invoked"
|
|
)
|
|
|
|
result = {}
|
|
with patch.dict(
|
|
self.funcs,
|
|
{
|
|
"boto_lambda.describe_function": MagicMock(
|
|
return_value={"error": "no such lambda"}
|
|
)
|
|
},
|
|
):
|
|
with TempSwaggerFile() as swagger_file:
|
|
result = self.salt_states["boto_apigateway.present"](
|
|
"api present",
|
|
"unit test api",
|
|
swagger_file,
|
|
"test",
|
|
False,
|
|
"arn:aws:iam::1234:role/apigatewayrole",
|
|
**conn_parameters
|
|
)
|
|
|
|
self.assertIs(result.get("result"), False)
|
|
self.assertNotIn(
|
|
"put_integration should not be invoked", result.get("comment", "")
|
|
)
|
|
self.assertIn("not find lambda function", result.get("comment", ""))
|
|
|
|
@pytest.mark.slow_test
|
|
def test_present_when_stage_associating_to_new_deployment_errored_on_put_integration(
|
|
self,
|
|
):
|
|
"""
|
|
Tests creation of a new api/model/resource given nothing has been created previously,
|
|
and we failed on adding an integration for the post method to the resource after
|
|
successful creation of top level api, model, resource objects.
|
|
"""
|
|
# no api existed
|
|
self.conn.get_rest_apis.return_value = no_apis_ret
|
|
# create top level api
|
|
self.conn.create_rest_api.return_value = api_ret
|
|
# no models existed in the newly created api
|
|
self.conn.get_model.side_effect = ClientError(error_content, "get_model")
|
|
# create model return values
|
|
self.conn.create_model.return_value = mock_model_ret
|
|
# various paths/resources already created
|
|
self.conn.get_resources.return_value = resources_ret
|
|
# the following should never be called
|
|
self.conn.create_resource.side_effect = ClientError(
|
|
error_content, "create_resource"
|
|
)
|
|
|
|
# create api method for POST
|
|
self.conn.put_method.return_value = method_ret
|
|
# create api method integration for POST
|
|
self.conn.put_integration.side_effect = ClientError(
|
|
error_content, "put_integration"
|
|
)
|
|
|
|
result = {}
|
|
with patch.dict(
|
|
self.funcs,
|
|
{
|
|
"boto_lambda.describe_function": MagicMock(
|
|
return_value={"function": function_ret}
|
|
)
|
|
},
|
|
):
|
|
with TempSwaggerFile() as swagger_file:
|
|
result = self.salt_states["boto_apigateway.present"](
|
|
"api present",
|
|
"unit test api",
|
|
swagger_file,
|
|
"test",
|
|
False,
|
|
"arn:aws:iam::1234:role/apigatewayrole",
|
|
**conn_parameters
|
|
)
|
|
|
|
self.assertIs(result.get("abort"), True)
|
|
self.assertIs(result.get("result"), False)
|
|
self.assertIn("put_integration", result.get("comment", ""))
|
|
|
|
@pytest.mark.slow_test
|
|
def test_present_when_stage_associating_to_new_deployment_errored_on_put_method_response(
|
|
self,
|
|
):
|
|
"""
|
|
Tests creation of a new api/model/resource given nothing has been created previously,
|
|
and we failed on adding a method response for the post method to the resource after
|
|
successful creation of top level api, model, resource objects.
|
|
"""
|
|
# no api existed
|
|
self.conn.get_rest_apis.return_value = no_apis_ret
|
|
# create top level api
|
|
self.conn.create_rest_api.return_value = api_ret
|
|
# no models existed in the newly created api
|
|
self.conn.get_model.side_effect = ClientError(error_content, "get_model")
|
|
# create model return values
|
|
self.conn.create_model.return_value = mock_model_ret
|
|
# various paths/resources already created
|
|
self.conn.get_resources.return_value = resources_ret
|
|
# the following should never be called
|
|
self.conn.create_resource.side_effect = ClientError(
|
|
error_content, "create_resource"
|
|
)
|
|
|
|
# create api method for POST
|
|
self.conn.put_method.return_value = method_ret
|
|
# create api method integration for POST
|
|
self.conn.put_integration.return_value = method_integration_ret
|
|
# create api method response for POST/200
|
|
self.conn.put_method_response.side_effect = ClientError(
|
|
error_content, "put_method_response"
|
|
)
|
|
|
|
result = {}
|
|
with patch.dict(
|
|
self.funcs,
|
|
{
|
|
"boto_lambda.describe_function": MagicMock(
|
|
return_value={"function": function_ret}
|
|
)
|
|
},
|
|
):
|
|
with TempSwaggerFile() as swagger_file:
|
|
result = self.salt_states["boto_apigateway.present"](
|
|
"api present",
|
|
"unit test api",
|
|
swagger_file,
|
|
"test",
|
|
False,
|
|
"arn:aws:iam::1234:role/apigatewayrole",
|
|
**conn_parameters
|
|
)
|
|
|
|
self.assertIs(result.get("abort"), True)
|
|
self.assertIs(result.get("result"), False)
|
|
self.assertIn("put_method_response", result.get("comment", ""))
|
|
|
|
@pytest.mark.slow_test
|
|
def test_present_when_stage_associating_to_new_deployment_errored_on_put_integration_response(
|
|
self,
|
|
):
|
|
"""
|
|
Tests creation of a new api/model/resource given nothing has been created previously,
|
|
and we failed on adding an integration response for the post method to the resource after
|
|
successful creation of top level api, model, resource objects.
|
|
"""
|
|
# no api existed
|
|
self.conn.get_rest_apis.return_value = no_apis_ret
|
|
# create top level api
|
|
self.conn.create_rest_api.return_value = api_ret
|
|
# no models existed in the newly created api
|
|
self.conn.get_model.side_effect = ClientError(error_content, "get_model")
|
|
# create model return values
|
|
self.conn.create_model.return_value = mock_model_ret
|
|
# various paths/resources already created
|
|
self.conn.get_resources.return_value = resources_ret
|
|
# the following should never be called
|
|
self.conn.create_resource.side_effect = ClientError(
|
|
error_content, "create_resource"
|
|
)
|
|
|
|
# create api method for POST
|
|
self.conn.put_method.return_value = method_ret
|
|
# create api method integration for POST
|
|
self.conn.put_integration.return_value = method_integration_ret
|
|
# create api method response for POST/200
|
|
self.conn.put_method_response.return_value = method_response_200_ret
|
|
# create api method integration response for POST
|
|
self.conn.put_integration_response.side_effect = ClientError(
|
|
error_content, "put_integration_response"
|
|
)
|
|
|
|
result = {}
|
|
with patch.dict(
|
|
self.funcs,
|
|
{
|
|
"boto_lambda.describe_function": MagicMock(
|
|
return_value={"function": function_ret}
|
|
)
|
|
},
|
|
):
|
|
with TempSwaggerFile() as swagger_file:
|
|
result = self.salt_states["boto_apigateway.present"](
|
|
"api present",
|
|
"unit test api",
|
|
swagger_file,
|
|
"test",
|
|
False,
|
|
"arn:aws:iam::1234:role/apigatewayrole",
|
|
**conn_parameters
|
|
)
|
|
|
|
self.assertIs(result.get("abort"), True)
|
|
self.assertIs(result.get("result"), False)
|
|
self.assertIn("put_integration_response", result.get("comment", ""))
|
|
|
|
def test_absent_when_rest_api_does_not_exist(self):
|
|
"""
|
|
Tests scenario where the given api_name does not exist, absent state should return True
|
|
with no changes.
|
|
"""
|
|
self.conn.get_rest_apis.return_value = apis_ret
|
|
self.conn.get_stage.side_effect = ClientError(
|
|
error_content, "get_stage should not be called"
|
|
)
|
|
|
|
result = self.salt_states["boto_apigateway.absent"](
|
|
"api present",
|
|
"no_such_rest_api",
|
|
"no_such_stage",
|
|
nuke_api=False,
|
|
**conn_parameters
|
|
)
|
|
|
|
self.assertIs(result.get("result"), True)
|
|
self.assertNotIn("get_stage should not be called", result.get("comment", ""))
|
|
self.assertEqual(result.get("changes"), {})
|
|
|
|
def test_absent_when_stage_is_invalid(self):
|
|
"""
|
|
Tests scenario where the stagename doesn't exist
|
|
"""
|
|
self.conn.get_rest_apis.return_value = apis_ret
|
|
self.conn.get_stage.return_value = stage1_deployment1_ret
|
|
self.conn.delete_stage.side_effect = ClientError(error_content, "delete_stage")
|
|
|
|
result = self.salt_states["boto_apigateway.absent"](
|
|
"api present",
|
|
"unit test api",
|
|
"no_such_stage",
|
|
nuke_api=False,
|
|
**conn_parameters
|
|
)
|
|
|
|
self.assertTrue(result.get("abort", False))
|
|
|
|
def test_absent_when_stage_is_valid_and_only_one_stage_is_associated_to_deployment(
|
|
self,
|
|
):
|
|
"""
|
|
Tests scenario where the stagename exists
|
|
"""
|
|
self.conn.get_rest_apis.return_value = apis_ret
|
|
self.conn.get_stage.return_value = stage1_deployment1_ret
|
|
self.conn.delete_stage.return_value = {
|
|
"ResponseMetadata": {
|
|
"HTTPStatusCode": 200,
|
|
"RequestId": "2d31072c-9d15-11e5-9977-6d9fcfda9c0a",
|
|
}
|
|
}
|
|
self.conn.get_stages.return_value = no_stages_ret
|
|
self.conn.delete_deployment.return_value = {
|
|
"ResponseMetadata": {
|
|
"HTTPStatusCode": 200,
|
|
"RequestId": "2d31072c-9d15-11e5-9977-6d9fcfda9c0a",
|
|
}
|
|
}
|
|
|
|
result = self.salt_states["boto_apigateway.absent"](
|
|
"api present", "unit test api", "test", nuke_api=False, **conn_parameters
|
|
)
|
|
|
|
self.assertTrue(result.get("result", False))
|
|
|
|
def test_absent_when_stage_is_valid_and_two_stages_are_associated_to_deployment(
|
|
self,
|
|
):
|
|
"""
|
|
Tests scenario where the stagename exists and there are two stages associated with same deployment
|
|
"""
|
|
self.conn.get_rest_apis.return_value = apis_ret
|
|
self.conn.get_stage.return_value = stage1_deployment1_ret
|
|
self.conn.delete_stage.return_value = {
|
|
"ResponseMetadata": {
|
|
"HTTPStatusCode": 200,
|
|
"RequestId": "2d31072c-9d15-11e5-9977-6d9fcfda9c0a",
|
|
}
|
|
}
|
|
self.conn.get_stages.return_value = stages_stage2_ret
|
|
|
|
result = self.salt_states["boto_apigateway.absent"](
|
|
"api present", "unit test api", "test", nuke_api=False, **conn_parameters
|
|
)
|
|
|
|
self.assertTrue(result.get("result", False))
|
|
|
|
def test_absent_when_failing_to_delete_a_deployment_no_longer_associated_with_any_stages(
|
|
self,
|
|
):
|
|
"""
|
|
Tests scenario where stagename exists and is deleted, but a failure occurs when trying to delete
|
|
the deployment which is no longer associated to any other stages
|
|
"""
|
|
self.conn.get_rest_apis.return_value = apis_ret
|
|
self.conn.get_stage.return_value = stage1_deployment1_ret
|
|
self.conn.delete_stage.return_value = {
|
|
"ResponseMetadata": {
|
|
"HTTPStatusCode": 200,
|
|
"RequestId": "2d31072c-9d15-11e5-9977-6d9fcfda9c0a",
|
|
}
|
|
}
|
|
self.conn.get_stages.return_value = no_stages_ret
|
|
self.conn.delete_deployment.side_effect = ClientError(
|
|
error_content, "delete_deployment"
|
|
)
|
|
|
|
result = self.salt_states["boto_apigateway.absent"](
|
|
"api present", "unit test api", "test", nuke_api=False, **conn_parameters
|
|
)
|
|
|
|
self.assertTrue(result.get("abort", False))
|
|
|
|
def test_absent_when_nuke_api_and_no_more_stages_deployments_remain(self):
|
|
"""
|
|
Tests scenario where the stagename exists and there are no stages associated with same deployment,
|
|
the api would be deleted.
|
|
"""
|
|
self.conn.get_rest_apis.return_value = apis_ret
|
|
self.conn.get_stage.return_value = stage1_deployment1_ret
|
|
self.conn.delete_stage.return_value = {
|
|
"ResponseMetadata": {
|
|
"HTTPStatusCode": 200,
|
|
"RequestId": "2d31072c-9d15-11e5-9977-6d9fcfda9c0a",
|
|
}
|
|
}
|
|
self.conn.get_stages.return_value = no_stages_ret
|
|
self.conn.get_deployments.return_value = deployments_ret
|
|
self.conn.delete_rest_api.return_value = {
|
|
"ResponseMetadata": {
|
|
"HTTPStatusCode": 200,
|
|
"RequestId": "2d31072c-9d15-11e5-9977-6d9fcfda9c0a",
|
|
}
|
|
}
|
|
|
|
result = self.salt_states["boto_apigateway.absent"](
|
|
"api present", "unit test api", "test", nuke_api=True, **conn_parameters
|
|
)
|
|
|
|
self.assertIs(result.get("result"), True)
|
|
self.assertIsNot(result.get("abort"), True)
|
|
self.assertIs(
|
|
result.get("changes", {})
|
|
.get("new", [{}])[0]
|
|
.get("delete_api", {})
|
|
.get("deleted"),
|
|
True,
|
|
)
|
|
|
|
def test_absent_when_nuke_api_and_other_stages_deployments_exist(self):
|
|
"""
|
|
Tests scenario where the stagename exists and there are two stages associated with same deployment,
|
|
though nuke_api is requested, due to remaining deployments, we will not call the delete_rest_api call.
|
|
"""
|
|
self.conn.get_rest_apis.return_value = apis_ret
|
|
self.conn.get_stage.return_value = stage1_deployment1_ret
|
|
self.conn.delete_stage.return_value = {
|
|
"ResponseMetadata": {
|
|
"HTTPStatusCode": 200,
|
|
"RequestId": "2d31072c-9d15-11e5-9977-6d9fcfda9c0a",
|
|
}
|
|
}
|
|
self.conn.get_stages.return_value = stages_stage2_ret
|
|
self.conn.get_deployments.return_value = deployments_ret
|
|
self.conn.delete_rest_api.side_effect = ClientError(
|
|
error_content, "unexpected_api_delete"
|
|
)
|
|
|
|
result = self.salt_states["boto_apigateway.absent"](
|
|
"api present", "unit test api", "test", nuke_api=True, **conn_parameters
|
|
)
|
|
|
|
self.assertIs(result.get("result"), True)
|
|
self.assertIsNot(result.get("abort"), True)
|
|
|
|
|
|
@pytest.mark.skipif(HAS_BOTO is False, reason="The boto module must be installed.")
|
|
@pytest.mark.skipif(
|
|
_has_required_boto() is False,
|
|
reason="The boto3 module must be greater than or equal to version {}".format(
|
|
required_boto3_version
|
|
),
|
|
)
|
|
@pytest.mark.skipif(
|
|
_has_required_botocore() is False,
|
|
reason="The botocore module must be greater than or equal to version {}".format(
|
|
required_botocore_version
|
|
),
|
|
)
|
|
class BotoApiGatewayUsagePlanTestCase(
|
|
BotoApiGatewayStateTestCaseBase, BotoApiGatewayTestCaseMixin
|
|
):
|
|
"""
|
|
TestCase for salt.modules.boto_apigateway state.module, usage_plans portion
|
|
"""
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_present_if_describe_fails(self, *args):
|
|
"""
|
|
Tests correct error processing for describe_usage_plan failure
|
|
"""
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
return_value={"error": "error"}
|
|
)
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_present(
|
|
"name", "plan_name", **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], False)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(
|
|
result["comment"], "Failed to describe existing usage plans"
|
|
)
|
|
self.assertIn("changes", result)
|
|
self.assertEqual(result["changes"], {})
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_present_if_there_is_no_such_plan_and_test_option_is_set(
|
|
self, *args
|
|
):
|
|
"""
|
|
TestCse for salt.modules.boto_apigateway state.module, checking that if __opts__['test'] is set
|
|
and usage plan does not exist, correct diagnostic will be returned
|
|
"""
|
|
with patch.dict(boto_apigateway.__opts__, {"test": True}):
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
return_value={"plans": []}
|
|
)
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_present(
|
|
"name", "plan_name", **conn_parameters
|
|
)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(
|
|
result["comment"], "a new usage plan plan_name would be created"
|
|
)
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], None)
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_present_if_create_usage_plan_fails(self, *args):
|
|
"""
|
|
Tests behavior for the case when creating a new usage plan fails
|
|
"""
|
|
with patch.dict(boto_apigateway.__opts__, {"test": False}):
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
return_value={"plans": []}
|
|
),
|
|
"boto_apigateway.create_usage_plan": MagicMock(
|
|
return_value={"error": "error"}
|
|
),
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_present(
|
|
"name", "plan_name", **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], False)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(
|
|
result["comment"], "Failed to create a usage plan plan_name, error"
|
|
)
|
|
self.assertIn("changes", result)
|
|
self.assertEqual(result["changes"], {})
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_present_if_plan_is_there_and_needs_no_updates(self, *args):
|
|
"""
|
|
Tests behavior for the case when plan is present and needs no updates
|
|
"""
|
|
with patch.dict(boto_apigateway.__opts__, {"test": False}):
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
return_value={"plans": [{"id": "planid", "name": "planname"}]}
|
|
),
|
|
"boto_apigateway.update_usage_plan": MagicMock(),
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_present(
|
|
"name", "plan_name", **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], True)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(
|
|
result["comment"],
|
|
"usage plan plan_name is already in a correct state",
|
|
)
|
|
self.assertIn("changes", result)
|
|
self.assertEqual(result["changes"], {})
|
|
|
|
self.assertTrue(
|
|
boto_apigateway.__salt__[
|
|
"boto_apigateway.update_usage_plan"
|
|
].call_count
|
|
== 0
|
|
)
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_present_if_plan_is_there_and_needs_updates_but_test_is_set(
|
|
self, *args
|
|
):
|
|
"""
|
|
Tests behavior when usage plan needs to be updated by tests option is set
|
|
"""
|
|
with patch.dict(boto_apigateway.__opts__, {"test": True}):
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
return_value={
|
|
"plans": [
|
|
{
|
|
"id": "planid",
|
|
"name": "planname",
|
|
"throttle": {"rateLimit": 10.0},
|
|
}
|
|
]
|
|
}
|
|
),
|
|
"boto_apigateway.update_usage_plan": MagicMock(),
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_present(
|
|
"name", "plan_name", **conn_parameters
|
|
)
|
|
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(
|
|
result["comment"], "a new usage plan plan_name would be updated"
|
|
)
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], None)
|
|
self.assertTrue(
|
|
boto_apigateway.__salt__[
|
|
"boto_apigateway.update_usage_plan"
|
|
].call_count
|
|
== 0
|
|
)
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_present_if_plan_is_there_and_needs_updates_but_update_fails(
|
|
self, *args
|
|
):
|
|
"""
|
|
Tests error processing for the case when updating an existing usage plan fails
|
|
"""
|
|
with patch.dict(boto_apigateway.__opts__, {"test": False}):
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
return_value={
|
|
"plans": [
|
|
{
|
|
"id": "planid",
|
|
"name": "planname",
|
|
"throttle": {"rateLimit": 10.0},
|
|
}
|
|
]
|
|
}
|
|
),
|
|
"boto_apigateway.update_usage_plan": MagicMock(
|
|
return_value={"error": "error"}
|
|
),
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_present(
|
|
"name", "plan_name", **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], False)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(
|
|
result["comment"], "Failed to update a usage plan plan_name, error"
|
|
)
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_present_if_plan_has_been_created(self, *args):
|
|
"""
|
|
Tests successful case for creating a new usage plan
|
|
"""
|
|
with patch.dict(boto_apigateway.__opts__, {"test": False}):
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
side_effect=[{"plans": []}, {"plans": [{"id": "id"}]}]
|
|
),
|
|
"boto_apigateway.create_usage_plan": MagicMock(
|
|
return_value={"created": True}
|
|
),
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_present(
|
|
"name", "plan_name", **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], True)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(
|
|
result["comment"], "A new usage plan plan_name has been created"
|
|
)
|
|
self.assertEqual(result["changes"]["old"], {"plan": None})
|
|
self.assertEqual(result["changes"]["new"], {"plan": {"id": "id"}})
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_present_if_plan_has_been_updated(self, *args):
|
|
"""
|
|
Tests successful case for updating a usage plan
|
|
"""
|
|
with patch.dict(boto_apigateway.__opts__, {"test": False}):
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
side_effect=[
|
|
{"plans": [{"id": "id"}]},
|
|
{
|
|
"plans": [
|
|
{
|
|
"id": "id",
|
|
"throttle": {"rateLimit": throttle_rateLimit},
|
|
}
|
|
]
|
|
},
|
|
]
|
|
),
|
|
"boto_apigateway.update_usage_plan": MagicMock(
|
|
return_value={"updated": True}
|
|
),
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_present(
|
|
"name",
|
|
"plan_name",
|
|
throttle={"rateLimit": throttle_rateLimit},
|
|
**conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], True)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(
|
|
result["comment"], "usage plan plan_name has been updated"
|
|
)
|
|
self.assertEqual(result["changes"]["old"], {"plan": {"id": "id"}})
|
|
self.assertEqual(
|
|
result["changes"]["new"],
|
|
{
|
|
"plan": {
|
|
"id": "id",
|
|
"throttle": {"rateLimit": throttle_rateLimit},
|
|
}
|
|
},
|
|
)
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_present_if_ValueError_is_raised(self, *args):
|
|
"""
|
|
Tests error processing for the case when ValueError is raised when creating a usage plan
|
|
"""
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
side_effect=ValueError("error")
|
|
)
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_present(
|
|
"name",
|
|
"plan_name",
|
|
throttle={"rateLimit": throttle_rateLimit},
|
|
**conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], False)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(result["comment"], repr(("error",)))
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_present_if_IOError_is_raised(self, *args):
|
|
"""
|
|
Tests error processing for the case when IOError is raised when creating a usage plan
|
|
"""
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
side_effect=IOError("error")
|
|
)
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_present(
|
|
"name",
|
|
"plan_name",
|
|
throttle={"rateLimit": throttle_rateLimit},
|
|
**conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], False)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(result["comment"], repr(("error",)))
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_absent_if_describe_fails(self, *args):
|
|
"""
|
|
Tests correct error processing for describe_usage_plan failure
|
|
"""
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
return_value={"error": "error"}
|
|
)
|
|
},
|
|
):
|
|
result = {}
|
|
|
|
result = boto_apigateway.usage_plan_absent(
|
|
"name", "plan_name", **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], False)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(
|
|
result["comment"], "Failed to describe existing usage plans"
|
|
)
|
|
self.assertIn("changes", result)
|
|
self.assertEqual(result["changes"], {})
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_absent_if_plan_is_not_present(self, *args):
|
|
"""
|
|
Tests behavior for the case when the plan that needs to be absent does not exist
|
|
"""
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
return_value={"plans": []}
|
|
)
|
|
},
|
|
):
|
|
result = {}
|
|
|
|
result = boto_apigateway.usage_plan_absent(
|
|
"name", "plan_name", **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], True)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(
|
|
result["comment"], "Usage plan plan_name does not exist already"
|
|
)
|
|
self.assertIn("changes", result)
|
|
self.assertEqual(result["changes"], {})
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_absent_if_plan_is_present_but_test_option_is_set(self, *args):
|
|
"""
|
|
Tests behavior for the case when usage plan needs to be deleted by tests option is set
|
|
"""
|
|
with patch.dict(boto_apigateway.__opts__, {"test": True}):
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
return_value={"plans": [{"id": "id"}]}
|
|
)
|
|
},
|
|
):
|
|
result = {}
|
|
|
|
result = boto_apigateway.usage_plan_absent(
|
|
"name", "plan_name", **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], None)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(
|
|
result["comment"],
|
|
"Usage plan plan_name exists and would be deleted",
|
|
)
|
|
self.assertIn("changes", result)
|
|
self.assertEqual(result["changes"], {})
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_absent_if_plan_is_present_but_delete_fails(self, *args):
|
|
"""
|
|
Tests correct error processing when deleting a usage plan fails
|
|
"""
|
|
with patch.dict(boto_apigateway.__opts__, {"test": False}):
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
return_value={"plans": [{"id": "id"}]}
|
|
),
|
|
"boto_apigateway.delete_usage_plan": MagicMock(
|
|
return_value={"error": "error"}
|
|
),
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_absent(
|
|
"name", "plan_name", **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], False)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(
|
|
result["comment"],
|
|
"Failed to delete usage plan plan_name, "
|
|
+ repr({"error": "error"}),
|
|
)
|
|
self.assertIn("changes", result)
|
|
self.assertEqual(result["changes"], {})
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_absent_if_plan_has_been_deleted(self, *args):
|
|
"""
|
|
Tests successful case for deleting a usage plan
|
|
"""
|
|
with patch.dict(boto_apigateway.__opts__, {"test": False}):
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
return_value={"plans": [{"id": "id"}]}
|
|
),
|
|
"boto_apigateway.delete_usage_plan": MagicMock(
|
|
return_value={"deleted": True}
|
|
),
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_absent(
|
|
"name", "plan_name", **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], True)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(
|
|
result["comment"], "Usage plan plan_name has been deleted"
|
|
)
|
|
self.assertIn("changes", result)
|
|
self.assertEqual(
|
|
result["changes"],
|
|
{"new": {"plan": None}, "old": {"plan": {"id": "id"}}},
|
|
)
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_absent_if_ValueError_is_raised(self, *args):
|
|
"""
|
|
Tests correct error processing for the case when ValueError is raised when deleting a usage plan
|
|
"""
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
side_effect=ValueError("error")
|
|
)
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_absent(
|
|
"name", "plan_name", **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], False)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(result["comment"], repr(("error",)))
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_absent_if_IOError_is_raised(self, *args):
|
|
"""
|
|
Tests correct error processing for the case when IOError is raised when deleting a usage plan
|
|
"""
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
side_effect=IOError("error")
|
|
)
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_absent(
|
|
"name", "plan_name", **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], False)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(result["comment"], repr(("error",)))
|
|
|
|
|
|
@pytest.mark.skipif(HAS_BOTO is False, reason="The boto module must be installed.")
|
|
@pytest.mark.skipif(
|
|
_has_required_boto() is False,
|
|
reason="The boto3 module must be greater than or equal to version {}".format(
|
|
required_boto3_version
|
|
),
|
|
)
|
|
@pytest.mark.skipif(
|
|
_has_required_botocore() is False,
|
|
reason="The botocore module must be greater than or equal to version {}".format(
|
|
required_botocore_version
|
|
),
|
|
)
|
|
class BotoApiGatewayUsagePlanAssociationTestCase(
|
|
BotoApiGatewayStateTestCaseBase, BotoApiGatewayTestCaseMixin
|
|
):
|
|
"""
|
|
TestCase for salt.modules.boto_apigateway state.module, usage_plans_association portion
|
|
"""
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_association_present_if_describe_fails(self, *args):
|
|
"""
|
|
Tests correct error processing for describe_usage_plan failure
|
|
"""
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
return_value={"error": "error"}
|
|
)
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_association_present(
|
|
"name", "plan_name", [association_stage_1], **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], False)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(
|
|
result["comment"], "Failed to describe existing usage plans"
|
|
)
|
|
self.assertIn("changes", result)
|
|
self.assertEqual(result["changes"], {})
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_association_present_if_plan_is_not_present(self, *args):
|
|
"""
|
|
Tests correct error processing if a plan for which association has been requested is not present
|
|
"""
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
return_value={"plans": []}
|
|
)
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_association_present(
|
|
"name", "plan_name", [association_stage_1], **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], False)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(result["comment"], "Usage plan plan_name does not exist")
|
|
self.assertIn("changes", result)
|
|
self.assertEqual(result["changes"], {})
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_association_present_if_multiple_plans_with_the_same_name_exist(
|
|
self, *args
|
|
):
|
|
"""
|
|
Tests correct error processing for the case when multiple plans with the same name exist
|
|
"""
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
return_value={"plans": [{"id": "id1"}, {"id": "id2"}]}
|
|
)
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_association_present(
|
|
"name", "plan_name", [association_stage_1], **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], False)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(
|
|
result["comment"],
|
|
"There are multiple usage plans with the same name - it is not"
|
|
" supported",
|
|
)
|
|
self.assertIn("changes", result)
|
|
self.assertEqual(result["changes"], {})
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_association_present_if_association_already_exists(self, *args):
|
|
"""
|
|
Tests the behavior for the case when requested association is already present
|
|
"""
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
return_value={
|
|
"plans": [{"id": "id1", "apiStages": [association_stage_1]}]
|
|
}
|
|
)
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_association_present(
|
|
"name", "plan_name", [association_stage_1], **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], True)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(
|
|
result["comment"], "Usage plan is already asssociated to all api stages"
|
|
)
|
|
self.assertIn("changes", result)
|
|
self.assertEqual(result["changes"], {})
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_association_present_if_update_fails(self, *args):
|
|
"""
|
|
Tests correct error processing for the case when adding associations fails
|
|
"""
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
return_value={
|
|
"plans": [{"id": "id1", "apiStages": [association_stage_1]}]
|
|
}
|
|
),
|
|
"boto_apigateway.attach_usage_plan_to_apis": MagicMock(
|
|
return_value={"error": "error"}
|
|
),
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_association_present(
|
|
"name", "plan_name", [association_stage_2], **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], False)
|
|
self.assertIn("comment", result)
|
|
self.assertTrue(
|
|
result["comment"].startswith("Failed to associate a usage plan")
|
|
)
|
|
self.assertIn("changes", result)
|
|
self.assertEqual(result["changes"], {})
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_association_present_success(self, *args):
|
|
"""
|
|
Tests successful case for adding usage plan associations to a given api stage
|
|
"""
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
return_value={
|
|
"plans": [{"id": "id1", "apiStages": [association_stage_1]}]
|
|
}
|
|
),
|
|
"boto_apigateway.attach_usage_plan_to_apis": MagicMock(
|
|
return_value={
|
|
"result": {
|
|
"apiStages": [association_stage_1, association_stage_2]
|
|
}
|
|
}
|
|
),
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_association_present(
|
|
"name", "plan_name", [association_stage_2], **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], True)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(
|
|
result["comment"], "successfully associated usage plan to apis"
|
|
)
|
|
self.assertIn("changes", result)
|
|
self.assertEqual(
|
|
result["changes"],
|
|
{
|
|
"new": [association_stage_1, association_stage_2],
|
|
"old": [association_stage_1],
|
|
},
|
|
)
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_association_present_if_value_error_is_thrown(self, *args):
|
|
"""
|
|
Tests correct error processing for the case when IOError is raised while trying to set usage plan associations
|
|
"""
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
side_effect=ValueError("error")
|
|
)
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_association_present(
|
|
"name", "plan_name", [], **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], False)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(result["comment"], repr(("error",)))
|
|
self.assertIn("changes", result)
|
|
self.assertEqual(result["changes"], {})
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_association_present_if_io_error_is_thrown(self, *args):
|
|
"""
|
|
Tests correct error processing for the case when IOError is raised while trying to set usage plan associations
|
|
"""
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
side_effect=IOError("error")
|
|
)
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_association_present(
|
|
"name", "plan_name", [], **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], False)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(result["comment"], repr(("error",)))
|
|
self.assertIn("changes", result)
|
|
self.assertEqual(result["changes"], {})
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_association_absent_if_describe_fails(self, *args):
|
|
"""
|
|
Tests correct error processing for describe_usage_plan failure
|
|
"""
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
return_value={"error": "error"}
|
|
)
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_association_absent(
|
|
"name", "plan_name", [association_stage_1], **conn_parameters
|
|
)
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], False)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(
|
|
result["comment"], "Failed to describe existing usage plans"
|
|
)
|
|
self.assertIn("changes", result)
|
|
self.assertEqual(result["changes"], {})
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_association_absent_if_plan_is_not_present(self, *args):
|
|
"""
|
|
Tests error processing for the case when plan for which associations need to be modified is not present
|
|
"""
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
return_value={"plans": []}
|
|
)
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_association_absent(
|
|
"name", "plan_name", [association_stage_1], **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], False)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(result["comment"], "Usage plan plan_name does not exist")
|
|
self.assertIn("changes", result)
|
|
self.assertEqual(result["changes"], {})
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_association_absent_if_multiple_plans_with_the_same_name_exist(
|
|
self, *args
|
|
):
|
|
"""
|
|
Tests the case when there are multiple plans with the same name but different Ids
|
|
"""
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
return_value={"plans": [{"id": "id1"}, {"id": "id2"}]}
|
|
)
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_association_absent(
|
|
"name", "plan_name", [association_stage_1], **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], False)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(
|
|
result["comment"],
|
|
"There are multiple usage plans with the same name - it is not"
|
|
" supported",
|
|
)
|
|
self.assertIn("changes", result)
|
|
self.assertEqual(result["changes"], {})
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_association_absent_if_plan_has_no_associations(self, *args):
|
|
"""
|
|
Tests the case when the plan has no associations at all
|
|
"""
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
return_value={"plans": [{"id": "id1", "apiStages": []}]}
|
|
)
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_association_absent(
|
|
"name", "plan_name", [association_stage_1], **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], True)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(
|
|
result["comment"],
|
|
"Usage plan plan_name has no associated stages already",
|
|
)
|
|
self.assertIn("changes", result)
|
|
self.assertEqual(result["changes"], {})
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_association_absent_if_plan_has_no_specific_association(
|
|
self, *args
|
|
):
|
|
"""
|
|
Tests the case when requested association is not present already
|
|
"""
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
return_value={
|
|
"plans": [{"id": "id1", "apiStages": [association_stage_1]}]
|
|
}
|
|
)
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_association_absent(
|
|
"name", "plan_name", [association_stage_2], **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], True)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(
|
|
result["comment"],
|
|
"Usage plan is already not asssociated to any api stages",
|
|
)
|
|
self.assertIn("changes", result)
|
|
self.assertEqual(result["changes"], {})
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_association_absent_if_detaching_association_fails(self, *args):
|
|
"""
|
|
Tests correct error processing when detaching the usage plan from the api function is called
|
|
"""
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
return_value={
|
|
"plans": [
|
|
{
|
|
"id": "id1",
|
|
"apiStages": [association_stage_1, association_stage_2],
|
|
}
|
|
]
|
|
}
|
|
),
|
|
"boto_apigateway.detach_usage_plan_from_apis": MagicMock(
|
|
return_value={"error": "error"}
|
|
),
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_association_absent(
|
|
"name", "plan_name", [association_stage_2], **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], False)
|
|
self.assertIn("comment", result)
|
|
self.assertTrue(
|
|
result["comment"].startswith(
|
|
"Failed to disassociate a usage plan plan_name from the apis"
|
|
)
|
|
)
|
|
self.assertIn("changes", result)
|
|
self.assertEqual(result["changes"], {})
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_association_absent_success(self, *args):
|
|
"""
|
|
Tests successful case of disaccosiation the usage plan from api stages
|
|
"""
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
return_value={
|
|
"plans": [
|
|
{
|
|
"id": "id1",
|
|
"apiStages": [association_stage_1, association_stage_2],
|
|
}
|
|
]
|
|
}
|
|
),
|
|
"boto_apigateway.detach_usage_plan_from_apis": MagicMock(
|
|
return_value={"result": {"apiStages": [association_stage_1]}}
|
|
),
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_association_absent(
|
|
"name", "plan_name", [association_stage_2], **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], True)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(
|
|
result["comment"], "successfully disassociated usage plan from apis"
|
|
)
|
|
self.assertIn("changes", result)
|
|
self.assertEqual(
|
|
result["changes"],
|
|
{
|
|
"new": [association_stage_1],
|
|
"old": [association_stage_1, association_stage_2],
|
|
},
|
|
)
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_association_absent_if_ValueError_is_raised(self, *args):
|
|
"""
|
|
Tests correct error processing for the case where ValueError is raised while trying to remove plan associations
|
|
"""
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
side_effect=ValueError("error")
|
|
)
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_association_absent(
|
|
"name", "plan_name", [association_stage_1], **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], False)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(result["comment"], repr(("error",)))
|
|
self.assertIn("changes", result)
|
|
self.assertEqual(result["changes"], {})
|
|
|
|
@pytest.mark.slow_test
|
|
def test_usage_plan_association_absent_if_IOError_is_raised(self, *args):
|
|
"""
|
|
Tests correct error processing for the case where IOError exception is raised while trying to remove plan associations
|
|
"""
|
|
with patch.dict(
|
|
boto_apigateway.__salt__,
|
|
{
|
|
"boto_apigateway.describe_usage_plans": MagicMock(
|
|
side_effect=IOError("error")
|
|
)
|
|
},
|
|
):
|
|
result = boto_apigateway.usage_plan_association_absent(
|
|
"name", "plan_name", [association_stage_1], **conn_parameters
|
|
)
|
|
|
|
self.assertIn("result", result)
|
|
self.assertEqual(result["result"], False)
|
|
self.assertIn("comment", result)
|
|
self.assertEqual(result["comment"], repr(("error",)))
|
|
self.assertIn("changes", result)
|
|
self.assertEqual(result["changes"], {})
|