New methods to the databrew service for recipes and rulesets. (#4996)
This commit is contained in:
parent
552385881c
commit
2a6ba0ddd1
@ -15,6 +15,11 @@ class RecipeAlreadyExistsException(AlreadyExistsException):
|
|||||||
super().__init__("Recipe")
|
super().__init__("Recipe")
|
||||||
|
|
||||||
|
|
||||||
|
class RulesetAlreadyExistsException(AlreadyExistsException):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__("Ruleset")
|
||||||
|
|
||||||
|
|
||||||
class EntityNotFoundException(DataBrewClientError):
|
class EntityNotFoundException(DataBrewClientError):
|
||||||
def __init__(self, msg):
|
def __init__(self, msg):
|
||||||
super().__init__("EntityNotFoundException", msg)
|
super().__init__("EntityNotFoundException", msg)
|
||||||
@ -23,3 +28,8 @@ class EntityNotFoundException(DataBrewClientError):
|
|||||||
class RecipeNotFoundException(EntityNotFoundException):
|
class RecipeNotFoundException(EntityNotFoundException):
|
||||||
def __init__(self, recipe_name):
|
def __init__(self, recipe_name):
|
||||||
super().__init__("Recipe %s not found." % recipe_name)
|
super().__init__("Recipe %s not found." % recipe_name)
|
||||||
|
|
||||||
|
|
||||||
|
class RulesetNotFoundException(EntityNotFoundException):
|
||||||
|
def __init__(self, recipe_name):
|
||||||
|
super().__init__("Ruleset %s not found." % recipe_name)
|
||||||
|
@ -5,6 +5,7 @@ from moto.core import BaseBackend, BaseModel
|
|||||||
from moto.core.utils import BackendDict
|
from moto.core.utils import BackendDict
|
||||||
from moto.utilities.paginator import paginate
|
from moto.utilities.paginator import paginate
|
||||||
from .exceptions import RecipeAlreadyExistsException, RecipeNotFoundException
|
from .exceptions import RecipeAlreadyExistsException, RecipeNotFoundException
|
||||||
|
from .exceptions import RulesetAlreadyExistsException, RulesetNotFoundException
|
||||||
|
|
||||||
|
|
||||||
class DataBrewBackend(BaseBackend):
|
class DataBrewBackend(BaseBackend):
|
||||||
@ -15,11 +16,18 @@ class DataBrewBackend(BaseBackend):
|
|||||||
"limit_default": 100,
|
"limit_default": 100,
|
||||||
"unique_attribute": "name",
|
"unique_attribute": "name",
|
||||||
},
|
},
|
||||||
|
"list_rulesets": {
|
||||||
|
"input_token": "next_token",
|
||||||
|
"limit_key": "max_results",
|
||||||
|
"limit_default": 100,
|
||||||
|
"unique_attribute": "name",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, region_name):
|
def __init__(self, region_name):
|
||||||
self.region_name = region_name
|
self.region_name = region_name
|
||||||
self.recipes = OrderedDict()
|
self.recipes = OrderedDict()
|
||||||
|
self.rulesets = OrderedDict()
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
"""Re-initialize all attributes for this instance."""
|
"""Re-initialize all attributes for this instance."""
|
||||||
@ -37,6 +45,20 @@ class DataBrewBackend(BaseBackend):
|
|||||||
self.recipes[recipe_name] = recipe
|
self.recipes[recipe_name] = recipe
|
||||||
return recipe
|
return recipe
|
||||||
|
|
||||||
|
def update_recipe(self, recipe_name, recipe_description, recipe_steps, tags):
|
||||||
|
if recipe_name not in self.recipes:
|
||||||
|
raise RecipeNotFoundException(recipe_name)
|
||||||
|
|
||||||
|
recipe = self.recipes[recipe_name]
|
||||||
|
if recipe_description is not None:
|
||||||
|
recipe.description = recipe_description
|
||||||
|
if recipe_steps is not None:
|
||||||
|
recipe.steps = recipe_steps
|
||||||
|
if tags is not None:
|
||||||
|
recipe.tags = tags
|
||||||
|
|
||||||
|
return recipe
|
||||||
|
|
||||||
@paginate(pagination_model=PAGINATION_MODEL)
|
@paginate(pagination_model=PAGINATION_MODEL)
|
||||||
def list_recipes(self):
|
def list_recipes(self):
|
||||||
return [self.recipes[key] for key in self.recipes] if self.recipes else []
|
return [self.recipes[key] for key in self.recipes] if self.recipes else []
|
||||||
@ -49,6 +71,52 @@ class DataBrewBackend(BaseBackend):
|
|||||||
raise RecipeNotFoundException(recipe_name)
|
raise RecipeNotFoundException(recipe_name)
|
||||||
return self.recipes[recipe_name]
|
return self.recipes[recipe_name]
|
||||||
|
|
||||||
|
def create_ruleset(
|
||||||
|
self, ruleset_name, ruleset_description, ruleset_rules, ruleset_target_arn, tags
|
||||||
|
):
|
||||||
|
if ruleset_name in self.rulesets:
|
||||||
|
raise RulesetAlreadyExistsException()
|
||||||
|
|
||||||
|
ruleset = FakeRuleset(
|
||||||
|
self.region_name,
|
||||||
|
ruleset_name,
|
||||||
|
ruleset_description,
|
||||||
|
ruleset_rules,
|
||||||
|
ruleset_target_arn,
|
||||||
|
tags,
|
||||||
|
)
|
||||||
|
self.rulesets[ruleset_name] = ruleset
|
||||||
|
return ruleset
|
||||||
|
|
||||||
|
def update_ruleset(self, ruleset_name, ruleset_description, ruleset_rules, tags):
|
||||||
|
if ruleset_name not in self.rulesets:
|
||||||
|
raise RulesetNotFoundException(ruleset_name)
|
||||||
|
|
||||||
|
ruleset = self.rulesets[ruleset_name]
|
||||||
|
if ruleset_description is not None:
|
||||||
|
ruleset.description = ruleset_description
|
||||||
|
if ruleset_rules is not None:
|
||||||
|
ruleset.rules = ruleset_rules
|
||||||
|
if tags is not None:
|
||||||
|
ruleset.tags = tags
|
||||||
|
|
||||||
|
return ruleset
|
||||||
|
|
||||||
|
def get_ruleset(self, ruleset_name):
|
||||||
|
if ruleset_name not in self.rulesets:
|
||||||
|
raise RulesetNotFoundException(ruleset_name)
|
||||||
|
return self.rulesets[ruleset_name]
|
||||||
|
|
||||||
|
@paginate(pagination_model=PAGINATION_MODEL)
|
||||||
|
def list_rulesets(self):
|
||||||
|
return list(self.rulesets.values())
|
||||||
|
|
||||||
|
def delete_ruleset(self, ruleset_name):
|
||||||
|
if ruleset_name not in self.rulesets:
|
||||||
|
raise RulesetNotFoundException(ruleset_name)
|
||||||
|
|
||||||
|
del self.rulesets[ruleset_name]
|
||||||
|
|
||||||
|
|
||||||
class FakeRecipe(BaseModel):
|
class FakeRecipe(BaseModel):
|
||||||
def __init__(
|
def __init__(
|
||||||
@ -71,4 +139,34 @@ class FakeRecipe(BaseModel):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class FakeRuleset(BaseModel):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
region_name,
|
||||||
|
ruleset_name,
|
||||||
|
ruleset_description,
|
||||||
|
ruleset_rules,
|
||||||
|
ruleset_target_arn,
|
||||||
|
tags,
|
||||||
|
):
|
||||||
|
self.region_name = region_name
|
||||||
|
self.name = ruleset_name
|
||||||
|
self.description = ruleset_description
|
||||||
|
self.rules = ruleset_rules
|
||||||
|
self.target_arn = ruleset_target_arn
|
||||||
|
self.created_time = datetime.now()
|
||||||
|
|
||||||
|
self.tags = tags
|
||||||
|
|
||||||
|
def as_dict(self):
|
||||||
|
return {
|
||||||
|
"Name": self.name,
|
||||||
|
"Rules": self.rules,
|
||||||
|
"Description": self.description,
|
||||||
|
"TargetArn": self.target_arn,
|
||||||
|
"CreateTime": self.created_time.isoformat(),
|
||||||
|
"Tags": self.tags or dict(),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
databrew_backends = BackendDict(DataBrewBackend, "databrew")
|
databrew_backends = BackendDict(DataBrewBackend, "databrew")
|
||||||
|
@ -50,12 +50,98 @@ class DataBrewResponse(BaseResponse):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def put_recipe_response(self, recipe_name):
|
||||||
|
recipe_description = self.parameters.get("Description")
|
||||||
|
recipe_steps = self.parameters.get("Steps")
|
||||||
|
tags = self.parameters.get("Tags")
|
||||||
|
|
||||||
|
recipe = self.databrew_backend.update_recipe(
|
||||||
|
recipe_name, recipe_description, recipe_steps, tags
|
||||||
|
)
|
||||||
|
return 200, {}, json.dumps(recipe.as_dict())
|
||||||
|
|
||||||
|
def get_recipe_response(self, recipe_name):
|
||||||
|
recipe = self.databrew_backend.get_recipe(recipe_name)
|
||||||
|
return 201, {}, json.dumps(recipe.as_dict())
|
||||||
|
|
||||||
@amzn_request_id
|
@amzn_request_id
|
||||||
def describe_recipe_response(self, request, full_url, headers):
|
def recipe_response(self, request, full_url, headers):
|
||||||
self.setup_class(request, full_url, headers)
|
self.setup_class(request, full_url, headers)
|
||||||
parsed_url = urlparse(full_url)
|
parsed_url = urlparse(full_url)
|
||||||
|
|
||||||
recipe_name = parsed_url.path.rstrip("/").rsplit("/", 1)[1]
|
recipe_name = parsed_url.path.rstrip("/").rsplit("/", 1)[1]
|
||||||
|
|
||||||
recipe = self.databrew_backend.get_recipe(recipe_name)
|
if request.method == "PUT":
|
||||||
return json.dumps(recipe.as_dict())
|
return self.put_recipe_response(recipe_name)
|
||||||
|
elif request.method == "GET":
|
||||||
|
return self.get_recipe_response(recipe_name)
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
|
def create_ruleset(self):
|
||||||
|
ruleset_description = self.parameters.get("Description")
|
||||||
|
ruleset_rules = self.parameters.get("Rules")
|
||||||
|
ruleset_name = self.parameters.get("Name")
|
||||||
|
ruleset_target_arn = self.parameters.get("TargetArn")
|
||||||
|
tags = self.parameters.get("Tags")
|
||||||
|
|
||||||
|
return json.dumps(
|
||||||
|
self.databrew_backend.create_ruleset(
|
||||||
|
ruleset_name,
|
||||||
|
ruleset_description,
|
||||||
|
ruleset_rules,
|
||||||
|
ruleset_target_arn,
|
||||||
|
tags,
|
||||||
|
).as_dict()
|
||||||
|
)
|
||||||
|
|
||||||
|
def put_ruleset_response(self, ruleset_name):
|
||||||
|
ruleset_description = self.parameters.get("Description")
|
||||||
|
ruleset_rules = self.parameters.get("Rules")
|
||||||
|
tags = self.parameters.get("Tags")
|
||||||
|
|
||||||
|
ruleset = self.databrew_backend.update_ruleset(
|
||||||
|
ruleset_name, ruleset_description, ruleset_rules, tags
|
||||||
|
)
|
||||||
|
return 200, {}, json.dumps(ruleset.as_dict())
|
||||||
|
|
||||||
|
def get_ruleset_response(self, ruleset_name):
|
||||||
|
ruleset = self.databrew_backend.get_ruleset(ruleset_name)
|
||||||
|
return 201, {}, json.dumps(ruleset.as_dict())
|
||||||
|
|
||||||
|
def delete_ruleset_response(self, ruleset_name):
|
||||||
|
self.databrew_backend.delete_ruleset(ruleset_name)
|
||||||
|
return 204, {}, ""
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
|
def ruleset_response(self, request, full_url, headers):
|
||||||
|
self.setup_class(request, full_url, headers)
|
||||||
|
parsed_url = urlparse(full_url)
|
||||||
|
|
||||||
|
ruleset_name = parsed_url.path.split("/")[-1]
|
||||||
|
|
||||||
|
if request.method == "PUT":
|
||||||
|
response = self.put_ruleset_response(ruleset_name)
|
||||||
|
return response
|
||||||
|
elif request.method == "GET":
|
||||||
|
return self.get_ruleset_response(ruleset_name)
|
||||||
|
elif request.method == "DELETE":
|
||||||
|
return self.delete_ruleset_response(ruleset_name)
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
|
def list_rulesets(self):
|
||||||
|
# https://docs.aws.amazon.com/databrew/latest/dg/API_ListRulesets.html
|
||||||
|
next_token = self._get_param("NextToken", self._get_param("nextToken"))
|
||||||
|
max_results = self._get_int_param(
|
||||||
|
"MaxResults", self._get_int_param("maxResults")
|
||||||
|
)
|
||||||
|
|
||||||
|
# pylint: disable=unexpected-keyword-arg, unbalanced-tuple-unpacking
|
||||||
|
ruleset_list, next_token = self.databrew_backend.list_rulesets(
|
||||||
|
next_token=next_token, max_results=max_results
|
||||||
|
)
|
||||||
|
return json.dumps(
|
||||||
|
{
|
||||||
|
"Rulesets": [ruleset.as_dict() for ruleset in ruleset_list],
|
||||||
|
"NextToken": next_token,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@ -4,5 +4,7 @@ url_bases = [r"https?://databrew\.(.+)\.amazonaws.com"]
|
|||||||
|
|
||||||
url_paths = {
|
url_paths = {
|
||||||
"{0}/recipes$": DataBrewResponse.dispatch,
|
"{0}/recipes$": DataBrewResponse.dispatch,
|
||||||
"{0}/recipes/(?P<recipe_name>[^/]+)$": DataBrewResponse().describe_recipe_response,
|
"{0}/recipes/(?P<recipe_name>[^/]+)$": DataBrewResponse().recipe_response,
|
||||||
|
"{0}/rulesets$": DataBrewResponse.dispatch,
|
||||||
|
"{0}/rulesets/(?P<ruleset_name>[^/]+)$": DataBrewResponse().ruleset_response,
|
||||||
}
|
}
|
||||||
|
@ -96,6 +96,46 @@ def test_describe_recipe():
|
|||||||
recipe["Steps"].should.have.length_of(1)
|
recipe["Steps"].should.have.length_of(1)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_databrew
|
||||||
|
def test_update_recipe():
|
||||||
|
client = _create_databrew_client()
|
||||||
|
response = _create_test_recipe(client)
|
||||||
|
|
||||||
|
recipe = client.update_recipe(
|
||||||
|
Name=response["Name"],
|
||||||
|
Steps=[
|
||||||
|
{
|
||||||
|
"Action": {
|
||||||
|
"Operation": "REMOVE_COMBINED",
|
||||||
|
"Parameters": {
|
||||||
|
"collapseConsecutiveWhitespace": "false",
|
||||||
|
"removeAllPunctuation": "false",
|
||||||
|
"removeAllQuotes": "false",
|
||||||
|
"removeAllWhitespace": "false",
|
||||||
|
"removeCustomCharacters": "true",
|
||||||
|
"removeCustomValue": "true",
|
||||||
|
"removeLeadingAndTrailingPunctuation": "false",
|
||||||
|
"removeLeadingAndTrailingQuotes": "false",
|
||||||
|
"removeLeadingAndTrailingWhitespace": "false",
|
||||||
|
"removeLetters": "false",
|
||||||
|
"removeNumbers": "false",
|
||||||
|
"removeSpecialCharacters": "true",
|
||||||
|
"sourceColumn": "FakeColumn",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
recipe["Name"].should.equal(response["Name"])
|
||||||
|
|
||||||
|
# Describe the recipe and change the changes
|
||||||
|
recipe = client.describe_recipe(Name=response["Name"])
|
||||||
|
recipe["Name"].should.equal(response["Name"])
|
||||||
|
recipe["Steps"].should.have.length_of(1)
|
||||||
|
recipe["Steps"][0]["Action"]["Parameters"]["removeCustomValue"].should.equal("true")
|
||||||
|
|
||||||
|
|
||||||
@mock_databrew
|
@mock_databrew
|
||||||
def test_describe_recipe_that_does_not_exist():
|
def test_describe_recipe_that_does_not_exist():
|
||||||
client = _create_databrew_client()
|
client = _create_databrew_client()
|
171
tests/test_databrew/test_databrew_rulesets.py
Normal file
171
tests/test_databrew/test_databrew_rulesets.py
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
import uuid
|
||||||
|
|
||||||
|
import boto3
|
||||||
|
import pytest
|
||||||
|
from botocore.exceptions import ClientError
|
||||||
|
|
||||||
|
from moto import mock_databrew
|
||||||
|
|
||||||
|
|
||||||
|
def _create_databrew_client():
|
||||||
|
client = boto3.client("databrew", region_name="us-west-1")
|
||||||
|
return client
|
||||||
|
|
||||||
|
|
||||||
|
def _create_test_ruleset(client, tags=None, ruleset_name=None):
|
||||||
|
if ruleset_name is None:
|
||||||
|
ruleset_name = str(uuid.uuid4())
|
||||||
|
|
||||||
|
return client.create_ruleset(
|
||||||
|
Name=ruleset_name,
|
||||||
|
TargetArn="arn:aws:databrew:eu-west-1:000000000000:dataset/fake-dataset",
|
||||||
|
Rules=[
|
||||||
|
{
|
||||||
|
"Name": "Assert values > 0",
|
||||||
|
"Disabled": False,
|
||||||
|
"CheckExpression": ":col1 > :val1",
|
||||||
|
"SubstitutionMap": {":col1": "`Value`", ":val1": "0"},
|
||||||
|
"Threshold": {
|
||||||
|
"Value": 100,
|
||||||
|
"Type": "GREATER_THAN_OR_EQUAL",
|
||||||
|
"Unit": "PERCENTAGE",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
Tags=tags or {},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _create_test_rulesets(client, count):
|
||||||
|
for _ in range(count):
|
||||||
|
_create_test_ruleset(client)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_databrew
|
||||||
|
def test_ruleset_list_when_empty():
|
||||||
|
client = _create_databrew_client()
|
||||||
|
|
||||||
|
response = client.list_rulesets()
|
||||||
|
response.should.have.key("Rulesets")
|
||||||
|
response["Rulesets"].should.have.length_of(0)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_databrew
|
||||||
|
def test_list_ruleset_with_max_results():
|
||||||
|
client = _create_databrew_client()
|
||||||
|
|
||||||
|
_create_test_rulesets(client, 4)
|
||||||
|
response = client.list_rulesets(MaxResults=2)
|
||||||
|
response["Rulesets"].should.have.length_of(2)
|
||||||
|
response.should.have.key("NextToken")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_databrew
|
||||||
|
def test_list_rulesets_from_next_token():
|
||||||
|
client = _create_databrew_client()
|
||||||
|
_create_test_rulesets(client, 10)
|
||||||
|
first_response = client.list_rulesets(MaxResults=3)
|
||||||
|
response = client.list_rulesets(NextToken=first_response["NextToken"])
|
||||||
|
response["Rulesets"].should.have.length_of(7)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_databrew
|
||||||
|
def test_list_rulesets_with_max_results_greater_than_actual_results():
|
||||||
|
client = _create_databrew_client()
|
||||||
|
_create_test_rulesets(client, 4)
|
||||||
|
response = client.list_rulesets(MaxResults=10)
|
||||||
|
response["Rulesets"].should.have.length_of(4)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_databrew
|
||||||
|
def test_describe_ruleset():
|
||||||
|
client = _create_databrew_client()
|
||||||
|
response = _create_test_ruleset(client)
|
||||||
|
|
||||||
|
ruleset = client.describe_ruleset(Name=response["Name"])
|
||||||
|
|
||||||
|
ruleset["Name"].should.equal(response["Name"])
|
||||||
|
ruleset["Rules"].should.have.length_of(1)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_databrew
|
||||||
|
def test_describe_ruleset_that_does_not_exist():
|
||||||
|
client = _create_databrew_client()
|
||||||
|
|
||||||
|
with pytest.raises(ClientError) as exc:
|
||||||
|
client.describe_ruleset(Name="DoseNotExist")
|
||||||
|
err = exc.value.response["Error"]
|
||||||
|
err["Code"].should.equal("EntityNotFoundException")
|
||||||
|
err["Message"].should.equal("Ruleset DoseNotExist not found.")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_databrew
|
||||||
|
def test_create_ruleset_that_already_exists():
|
||||||
|
client = _create_databrew_client()
|
||||||
|
|
||||||
|
response = _create_test_ruleset(client)
|
||||||
|
|
||||||
|
with pytest.raises(ClientError) as exc:
|
||||||
|
_create_test_ruleset(client, ruleset_name=response["Name"])
|
||||||
|
err = exc.value.response["Error"]
|
||||||
|
err["Code"].should.equal("AlreadyExistsException")
|
||||||
|
err["Message"].should.equal("Ruleset already exists.")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_databrew
|
||||||
|
def test_delete_ruleset():
|
||||||
|
client = _create_databrew_client()
|
||||||
|
response = _create_test_ruleset(client)
|
||||||
|
|
||||||
|
# Check ruleset exists
|
||||||
|
ruleset = client.describe_ruleset(Name=response["Name"])
|
||||||
|
ruleset["Name"].should.equal(response["Name"])
|
||||||
|
|
||||||
|
# Delete the ruleset
|
||||||
|
client.delete_ruleset(Name=response["Name"])
|
||||||
|
|
||||||
|
# Check it does not exist anymore
|
||||||
|
with pytest.raises(ClientError) as exc:
|
||||||
|
client.describe_ruleset(Name=response["Name"])
|
||||||
|
|
||||||
|
err = exc.value.response["Error"]
|
||||||
|
err["Code"].should.equal("EntityNotFoundException")
|
||||||
|
err["Message"].should.equal(f"Ruleset {response['Name']} not found.")
|
||||||
|
|
||||||
|
# Check that a ruleset that does not exist errors
|
||||||
|
with pytest.raises(ClientError) as exc:
|
||||||
|
client.delete_ruleset(Name=response["Name"])
|
||||||
|
err = exc.value.response["Error"]
|
||||||
|
err["Code"].should.equal("EntityNotFoundException")
|
||||||
|
err["Message"].should.equal(f"Ruleset {response['Name']} not found.")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_databrew
|
||||||
|
def test_update_ruleset():
|
||||||
|
client = _create_databrew_client()
|
||||||
|
response = _create_test_ruleset(client)
|
||||||
|
|
||||||
|
# Update the ruleset and check response
|
||||||
|
ruleset = client.update_ruleset(
|
||||||
|
Name=response["Name"],
|
||||||
|
Rules=[
|
||||||
|
{
|
||||||
|
"Name": "Assert values > 0",
|
||||||
|
"Disabled": False,
|
||||||
|
"CheckExpression": ":col1 > :val1",
|
||||||
|
"SubstitutionMap": {":col1": "`Value`", ":val1": "10"},
|
||||||
|
"Threshold": {
|
||||||
|
"Value": 100,
|
||||||
|
"Type": "GREATER_THAN_OR_EQUAL",
|
||||||
|
"Unit": "PERCENTAGE",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
ruleset["Name"].should.equal(response["Name"])
|
||||||
|
|
||||||
|
# Describe the ruleset and check the changes
|
||||||
|
ruleset = client.describe_ruleset(Name=response["Name"])
|
||||||
|
ruleset["Name"].should.equal(response["Name"])
|
||||||
|
ruleset["Rules"].should.have.length_of(1)
|
||||||
|
ruleset["Rules"][0]["SubstitutionMap"][":val1"].should.equal("10")
|
Loading…
x
Reference in New Issue
Block a user