396 lines
11 KiB
Python
396 lines
11 KiB
Python
import json
|
|
|
|
import pytest
|
|
import sure # noqa # pylint: disable=unused-import
|
|
|
|
from moto.ecr.exceptions import InvalidParameterException
|
|
from moto.ecr.policy_validation import EcrLifecyclePolicyValidator
|
|
|
|
|
|
def test_validate():
|
|
# given
|
|
policy = {
|
|
"rules": [
|
|
{
|
|
"rulePriority": 1,
|
|
"description": "test policy",
|
|
"selection": {
|
|
"tagStatus": "untagged",
|
|
"countType": "imageCountMoreThan",
|
|
"countNumber": 30,
|
|
},
|
|
"action": {"type": "expire"},
|
|
},
|
|
{
|
|
"rulePriority": 2,
|
|
"description": "test policy",
|
|
"selection": {
|
|
"tagStatus": "tagged",
|
|
"tagPrefixList": ["3.9"],
|
|
"countType": "sinceImagePushed",
|
|
"countUnit": "days",
|
|
"countNumber": 30,
|
|
},
|
|
"action": {"type": "expire"},
|
|
},
|
|
]
|
|
}
|
|
|
|
# when/then
|
|
validator = EcrLifecyclePolicyValidator(json.dumps(policy))
|
|
validator.validate()
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"policy",
|
|
[
|
|
"some invalid input",
|
|
[
|
|
{
|
|
"rulePriority": 1,
|
|
"description": "test policy",
|
|
"selection": {
|
|
"tagStatus": "untagged",
|
|
"countType": "imageCountMoreThan",
|
|
"countNumber": 30,
|
|
},
|
|
"action": {"type": "expire"},
|
|
}
|
|
],
|
|
],
|
|
ids=["not_json", "not_dict"],
|
|
)
|
|
def test_validate_error_parse(policy):
|
|
# given
|
|
|
|
# when
|
|
with pytest.raises(InvalidParameterException) as e:
|
|
validator = EcrLifecyclePolicyValidator(json.dumps(policy))
|
|
validator.validate()
|
|
|
|
# then
|
|
ex = e.value
|
|
ex.code.should.equal(400)
|
|
ex.error_type.should.equal("InvalidParameterException")
|
|
ex.message.should.equal(
|
|
"Invalid parameter at 'LifecyclePolicyText' failed to satisfy constraint: "
|
|
"'Lifecycle policy validation failure: "
|
|
"Could not map policyString into LifecyclePolicy.'"
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"policy",
|
|
[
|
|
{"no_rules": "test"},
|
|
{
|
|
"rules": {
|
|
"rulePriority": 1,
|
|
"description": "test policy",
|
|
"selection": {
|
|
"tagStatus": "untagged",
|
|
"countType": "imageCountMoreThan",
|
|
"countNumber": 30,
|
|
},
|
|
"action": {"type": "expire"},
|
|
},
|
|
},
|
|
],
|
|
ids=["no_rules", "not_list"],
|
|
)
|
|
def test_validate_error_extract_rules(policy):
|
|
# given
|
|
|
|
# when
|
|
with pytest.raises(InvalidParameterException) as e:
|
|
validator = EcrLifecyclePolicyValidator(json.dumps(policy))
|
|
validator.validate()
|
|
|
|
# then
|
|
ex = e.value
|
|
ex.code.should.equal(400)
|
|
ex.error_type.should.equal("InvalidParameterException")
|
|
ex.message.should.equal(
|
|
"Invalid parameter at 'LifecyclePolicyText' failed to satisfy constraint: "
|
|
"'Lifecycle policy validation failure: "
|
|
'object has missing required properties (["rules"])\''
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("rule", ["not_dict"], ids=["not_dict"])
|
|
def test_validate_error_rule_type(rule):
|
|
# given
|
|
|
|
# when
|
|
with pytest.raises(InvalidParameterException) as e:
|
|
validator = EcrLifecyclePolicyValidator(json.dumps({"rules": [rule]}))
|
|
validator.validate()
|
|
|
|
# then
|
|
ex = e.value
|
|
ex.code.should.equal(400)
|
|
ex.error_type.should.equal("InvalidParameterException")
|
|
ex.message.should.equal(
|
|
"Invalid parameter at 'LifecyclePolicyText' failed to satisfy constraint: "
|
|
"'Lifecycle policy validation failure: "
|
|
f'instance type ({type(rule)}) does not match any allowed primitive type (allowed: ["object"])\''
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
["rule", "error_msg"],
|
|
[
|
|
[
|
|
{
|
|
"description": "test policy",
|
|
"selection": {
|
|
"tagStatus": "untagged",
|
|
"countType": "imageCountMoreThan",
|
|
"countNumber": 30,
|
|
},
|
|
"action": {"type": "expire"},
|
|
},
|
|
'object has missing required properties (["rulePriority"])\'',
|
|
],
|
|
[
|
|
{
|
|
"rulePriority": 1,
|
|
"description": "test policy",
|
|
"action": {"type": "expire"},
|
|
},
|
|
'object has missing required properties (["selection"])\'',
|
|
],
|
|
[
|
|
{
|
|
"rulePriority": 1,
|
|
"description": "test policy",
|
|
"selection": {
|
|
"tagStatus": "untagged",
|
|
"countType": "imageCountMoreThan",
|
|
"countNumber": 30,
|
|
},
|
|
},
|
|
'object has missing required properties (["action"])\'',
|
|
],
|
|
[
|
|
{
|
|
"rulePriority": 1,
|
|
"selection": {
|
|
"tagStatus": "untagged",
|
|
"countType": "imageCountMoreThan",
|
|
"countNumber": 30,
|
|
},
|
|
"action": {"type": "expire"},
|
|
"unknown": 123,
|
|
},
|
|
'object instance has properties which are not allowed by the schema: (["unknown"])\'',
|
|
],
|
|
],
|
|
ids=["missing_rulePriority", "missing_selection", "missing_action", "unknown"],
|
|
)
|
|
def test_validate_error_rule_properties(rule, error_msg):
|
|
# given
|
|
|
|
# when
|
|
with pytest.raises(InvalidParameterException) as e:
|
|
validator = EcrLifecyclePolicyValidator(json.dumps({"rules": [rule]}))
|
|
validator.validate()
|
|
|
|
# then
|
|
ex = e.value
|
|
ex.code.should.equal(400)
|
|
ex.error_type.should.equal("InvalidParameterException")
|
|
ex.message.should.equal(
|
|
"".join(
|
|
[
|
|
"Invalid parameter at 'LifecyclePolicyText' failed to satisfy constraint: "
|
|
"'Lifecycle policy validation failure: ",
|
|
error_msg,
|
|
]
|
|
)
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
["action", "error_msg"],
|
|
[
|
|
[{}, 'object has missing required properties (["type"])\''],
|
|
[
|
|
{"type": "expire", "unknown": 123},
|
|
(
|
|
"object instance has properties "
|
|
'which are not allowed by the schema: (["unknown"])\''
|
|
),
|
|
],
|
|
[
|
|
{"type": "keep"},
|
|
(
|
|
"instance value (keep) not found in enum "
|
|
':(possible values: ["expire"])\''
|
|
),
|
|
],
|
|
],
|
|
ids=["missing_type", "unknown", "unknown_type_value"],
|
|
)
|
|
def test_validate_error_action_properties(action, error_msg):
|
|
# given
|
|
|
|
# when
|
|
with pytest.raises(InvalidParameterException) as e:
|
|
validator = EcrLifecyclePolicyValidator(
|
|
json.dumps(
|
|
{
|
|
"rules": [
|
|
{
|
|
"rulePriority": 1,
|
|
"selection": {
|
|
"tagStatus": "untagged",
|
|
"countType": "imageCountMoreThan",
|
|
"countNumber": 30,
|
|
},
|
|
"action": action,
|
|
}
|
|
]
|
|
}
|
|
)
|
|
)
|
|
validator.validate()
|
|
|
|
# then
|
|
ex = e.value
|
|
ex.code.should.equal(400)
|
|
ex.error_type.should.equal("InvalidParameterException")
|
|
ex.message.should.equal(
|
|
"".join(
|
|
[
|
|
"Invalid parameter at 'LifecyclePolicyText' failed to satisfy constraint: "
|
|
"'Lifecycle policy validation failure: ",
|
|
error_msg,
|
|
]
|
|
)
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
["selection", "error_msg"],
|
|
[
|
|
[
|
|
{"countType": "imageCountMoreThan", "countNumber": 30},
|
|
'object has missing required properties (["tagStatus"])\'',
|
|
],
|
|
[
|
|
{"tagStatus": "untagged", "countNumber": 30},
|
|
'object has missing required properties (["countType"])\'',
|
|
],
|
|
[
|
|
{"tagStatus": "untagged", "countType": "imageCountMoreThan"},
|
|
'object has missing required properties (["countNumber"])\'',
|
|
],
|
|
[
|
|
{
|
|
"tagStatus": "untagged",
|
|
"countType": "imageCountMoreThan",
|
|
"countNumber": 30,
|
|
"unknown": 123,
|
|
},
|
|
(
|
|
"object instance has properties "
|
|
'which are not allowed by the schema: (["unknown"])\''
|
|
),
|
|
],
|
|
[
|
|
{
|
|
"tagStatus": "unknown",
|
|
"countType": "imageCountMoreThan",
|
|
"countNumber": 30,
|
|
},
|
|
(
|
|
"instance value (unknown) not found in enum "
|
|
':(possible values: ["any", "tagged", "untagged"])\''
|
|
),
|
|
],
|
|
[
|
|
{"tagStatus": "untagged", "countType": "unknown", "countNumber": 30},
|
|
"instance failed to match exactly one schema (matched 0 out of 2)",
|
|
],
|
|
[
|
|
{
|
|
"tagStatus": "untagged",
|
|
"countType": "sinceImagePushed",
|
|
"countUnit": "unknown",
|
|
"countNumber": 30,
|
|
},
|
|
(
|
|
"instance value (unknown) not found in enum "
|
|
':(possible values: ["days"])\''
|
|
),
|
|
],
|
|
[
|
|
{
|
|
"tagStatus": "untagged",
|
|
"countType": "imageCountMoreThan",
|
|
"countNumber": 0,
|
|
},
|
|
(
|
|
"numeric instance is lower than the required minimum "
|
|
"(minimum: 1, found: 0)"
|
|
),
|
|
],
|
|
[
|
|
{
|
|
"tagStatus": "untagged",
|
|
"countType": "imageCountMoreThan",
|
|
"countNumber": -1,
|
|
},
|
|
(
|
|
"numeric instance is lower than the required minimum "
|
|
"(minimum: 1, found: -1)"
|
|
),
|
|
],
|
|
],
|
|
ids=[
|
|
"missing_tagStatus",
|
|
"missing_countType",
|
|
"missing_countNumber",
|
|
"unknown",
|
|
"unknown_tagStatus_value",
|
|
"unknown_countType_value",
|
|
"unknown_countUnit_value",
|
|
"zero_countNumber_value",
|
|
"negative_countNumber_value",
|
|
],
|
|
)
|
|
def test_validate_error_selection_properties(selection, error_msg):
|
|
# given
|
|
|
|
# when
|
|
with pytest.raises(InvalidParameterException) as e:
|
|
validator = EcrLifecyclePolicyValidator(
|
|
json.dumps(
|
|
{
|
|
"rules": [
|
|
{
|
|
"rulePriority": 1,
|
|
"selection": selection,
|
|
"action": {"type": "expire"},
|
|
}
|
|
]
|
|
}
|
|
)
|
|
)
|
|
validator.validate()
|
|
|
|
# then
|
|
ex = e.value
|
|
ex.code.should.equal(400)
|
|
ex.error_type.should.equal("InvalidParameterException")
|
|
ex.message.should.equal(
|
|
"".join(
|
|
[
|
|
"Invalid parameter at 'LifecyclePolicyText' failed to satisfy constraint: "
|
|
"'Lifecycle policy validation failure: ",
|
|
error_msg,
|
|
]
|
|
)
|
|
)
|