Skip to content

Commit

Permalink
Merge pull request #141 from GarnerCorp/master
Browse files Browse the repository at this point in the history
Add `equal` operator
  • Loading branch information
eerkunt authored Aug 9, 2019
2 parents e21c526 + 6ab2302 commit d1865d1
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 9 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,11 @@ Steps are the functional tests that is actually executing necessary task to vali
| WHEN | I `{math_formula}` them | `action`: `math_formula` |
| WHEN | its `{key}` is `{value}`<br>its `{key}` has `{value}`<br>its `{key}` contains `{value}`<br>its `{key}` includes `{value}` | `key`: any property that resource have (e.g. name, address, etc. ) `address` will give the terraform object name<br>`value`: any string or numeric value that the property has.<br>_Found resources from previous step will be filtered based on these values._ |
| WHEN | its `{key}` is not `{value}`<br>its `{key}` has not `{value}`<br>its `{key}` does not contain `{value}`<br>its `{key}` does not include `{value}` | `key`: any property that resource have (e.g. name, address, etc. ) `address` will give the terraform object name<br>`value`: any string, bool or numeric value that the property has.<br>_Found resources from previous step will be filtered based on these values._ |
| THEN | I expect the result is `{operator}` than `{number}`<br>Its value must be `{operator}` than `{number}` | `operator`: `more`, `more and equal`, `less`, `less and equal`<br>`number`: an integer |
| THEN | I expect the result is `{operator}` than/to `{number}`<br>Its value must be `{operator}` than/to `{number}` | `operator`: `more`, `more and equal`, `less`, `less and equal`, `equal`<br>`number`: an integer |
| WHEN<br>THEN | it contain `{something}`<br>it contains `{something}`<br>it must contain `{something}` | `something`: any property within terraform resoruce/provider/etc. (e.g. `access_key`, `ingress` ) |
| THEN | `{property}` is enabled<br>`{property}` must be enabled | `property`: can be either a generic property from your terraform configuration or templated ones like below for some resources;<br>* `encryption at rest`<br>* `encrytion in flight`|
| THEN | its value `{condition}` match the "`{search_regex}`" regex | `condition`: `must` or `must not`<br>`search_regex`: the regular expression of the searching value |
| THEN | its value `{condition}` be `{value}` | `condition`: `must` or `must not`<br>`value`: the matching value |
| WHEN<br>THEN | its value must be set by a variable | |
| THEN | it must `{condition}` have `{proto}` protocol and port `{port}` for `{cidr}` | `{condition}`: only,not<br>`proto`: tcp, udp<br>`port`: integer port number (or a port range by using `-` delimeter between port ranges [e.g. 80-84])<br>`cidr`: IP/Cidr |
| THEN | the scenario fails<br>the scenario should fail<br>it fails<br>it should fail<br>it must fail | None |
Expand Down
6 changes: 6 additions & 0 deletions example/example_01/aws/data.example.feature
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,9 @@ Feature: Data example feature
When it contains zone_ids
And I count them
Then I expect the result is greater than 2

Scenario: Subnet Count
Given I have aws_availability_zones data defined
When it contains zone_ids
And I count them
Then I expect the result is equal to 3
9 changes: 4 additions & 5 deletions example/example_01/aws/resource_filtering.feature
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ Feature: Resource Filtering example
When its address is aws_s3_bucket.s3_bucket_prod
And it contains tags
Then it must contain <tag_keys>
And its value must match the "<pattern>" regex
And its value must be <string>

Examples:
| tag_keys | pattern |
| Data Classification | ^PRIVATE$ |
| Data Residency | ^EU$ |

| tag_keys | string |
| Data Classification | PRIVATE |
| Data Residency | EU |
2 changes: 1 addition & 1 deletion terraform_compliance/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from radish.main import main as call_radish

__app_name__ = "terraform-compliance"
__version__ = "1.0.36"
__version__ = "1.0.37"


print('{} v{} initiated\n'.format(__app_name__, __version__))
Expand Down
11 changes: 11 additions & 0 deletions terraform_compliance/steps/steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,8 @@ def i_action_them(_step_obj, action_type):

@then(u'Its value must be {operator:ANY} than {number:d}')
@then(u'I expect the result is {operator:ANY} than {number:d}')
@then(u'Its value must be {operator:ANY} to {number:d}')
@then(u'I expect the result is {operator:ANY} to {number:d}')
def i_expect_the_result_is_operator_than_number(_step_obj, operator, number, _stash=EmptyStash):
values = _step_obj.context.stash if _stash is EmptyStash else _stash

Expand All @@ -399,12 +401,15 @@ def i_expect_the_result_is_operator_than_number(_step_obj, operator, number, _st
assert values < number, "{} is not less than {}".format(values, number)
elif operator in ("less and equal", "lesser and equal", "smaller and equal"):
assert values <= number, "{} is not less and equal than {}".format(values, number)
elif operator in ("equal",):
assert values == number, "{} is not equal to {}".format(values, number)
else:
raise TerraformComplianceNotImplemented('Invalid operator: {}'.format(operator))

elif type(values) is Null:
raise TerraformComplianceNotImplemented('Null/Empty value found on {}'.format(_step_obj.context.type))


@step(u'its value {condition:ANY} match the "{search_regex}" regex')
def its_value_condition_match_the_search_regex_regex(_step_obj, condition, search_regex, _stash=EmptyStash):
def fail(condition, name=None):
Expand Down Expand Up @@ -444,6 +449,12 @@ def fail(condition, name=None):
for key, value in values.items():
its_value_condition_match_the_search_regex_regex(_step_obj, condition, search_regex, value)


@step(u'its value {condition:ANY} be {match:ANY}')
def its_value_condition_equal(_step_obj, condition, match, _stash=EmptyStash):
its_value_condition_match_the_search_regex_regex(_step_obj, condition, "^" + re.escape(match) + "$", _stash)


@then(u'the scenario fails')
@then(u'the scenario should fail')
@then(u'it fails')
Expand Down
40 changes: 38 additions & 2 deletions tests/terraform_compliance/steps/test_main_steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
its_value_condition_match_the_search_regex_regex,
it_condition_have_proto_protocol_and_port_port_for_cidr,
it_fails,
its_key_is_value, its_key_is_not_value
its_key_is_value, its_key_is_not_value,
its_value_condition_equal
)
from terraform_compliance.common.exceptions import TerraformComplianceNotImplemented, Failure, TerraformComplianceInternalFailure
from tests.mocks import MockedStep, MockedWorld, MockedTerraformPropertyList, MockedTerraformResourceList, MockedTerraformResource
Expand Down Expand Up @@ -311,6 +312,14 @@ def test_i_expect_the_result_is_operator_than_number_less_and_equal(self):
i_expect_the_result_is_operator_than_number(step, 'less and equal', 41)
self.assertEqual(str(err.exception), '42 is not less and equal than 41')

def test_i_expect_the_result_is_operator_than_number_equal(self):
step = MockedStep()
step.context.stash = {'values': 42}
self.assertIsNone(i_expect_the_result_is_operator_than_number(step, 'equal', 42))
with self.assertRaises(AssertionError) as err:
i_expect_the_result_is_operator_than_number(step, 'equal', 41)
self.assertEqual(str(err.exception), '42 is not equal to 41')

def test_i_expect_the_result_is_more_than_number_failure(self):
step = MockedStep()
step.context.stash = dict(values=3)
Expand Down Expand Up @@ -478,6 +487,8 @@ def test_its_value_condition_match_the_search_regex_regex_null_value_is_parsed(s

with self.assertRaises(Failure):
its_value_condition_match_the_search_regex_regex(step, 'must', 'something')
with self.assertRaises(Failure):
its_value_condition_equal(step, 'must', 'something')

def test_its_value_condition_match_the_search_regex_regex_success(self):
step = MockedStep()
Expand Down Expand Up @@ -509,6 +520,31 @@ def test_its_value_condition_match_the_search_regex_regex_success(self):
self.assertEqual(its_value_condition_match_the_search_regex_regex(step, 'must not', 'some_.*'), None)
self.assertEqual(its_value_condition_match_the_search_regex_regex(step, 'must not', 'some_other.*'), None)

def test_its_value_condition_equals(self):
step = MockedStep()
expected_value = r"https://www.stackoverflow.com[as](.*)\s\t+$"
step.context.stash = [
{
'address': 'some_resource.id',
'type': 'some_resource_type',
'name': 'some_name',
'values': {
'some_key': expected_value
}
}
]
step.context.type = 'resource'
step.context.name = 'some_name'
step.context.property_name = 'tags'
step.context_sensitive_sentence = 'must'

self.assertEqual(its_value_condition_equal(step, 'must', expected_value), None)
self.assertEqual(its_value_condition_equal(step, 'must not', expected_value * 2), None)

with self.assertRaises(Failure):
self.assertEqual(its_value_condition_equal(step, 'must', expected_value + ' '), None)
self.assertEqual(its_value_condition_equal(step, 'must not', expected_value), None)

def test_its_key_is_not_value_exist_in_values_bool(self):
step = MockedStep()
step.context.stash = [
Expand Down Expand Up @@ -617,4 +653,4 @@ def test_its_key_is_not_value_exist_in_values_int(self):
]
its_key_is_not_value(step, 'storage_encrypted', 1)
self.assertTrue(type(step.context.stash) is list)
self.assertEqual(step.context.stash[0]['some_key'], 'some_other_value')
self.assertEqual(step.context.stash[0]['some_key'], 'some_other_value')

0 comments on commit d1865d1

Please sign in to comment.