Skip to content

Commit

Permalink
Implement multi-assertion check
Browse files Browse the repository at this point in the history
  • Loading branch information
KyleKotowick committed Jan 18, 2025
1 parent 5df1177 commit f98059f
Show file tree
Hide file tree
Showing 11 changed files with 256 additions and 4 deletions.
80 changes: 80 additions & 0 deletions .github/workflows/CICD.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,50 @@ jobs:
uses: Invicton-Labs/terraform-module-testing/[email protected]
with:
tf_path: tests/pass-condition-message-delayed

- name: Initialize - Pass - Multi
id: init-pass-multi
uses: Invicton-Labs/terraform-module-testing/[email protected]
with:
tf_path: tests/pass-multi
- name: Run Tests - Pass - Multi
id: tests-pass-multi
uses: Invicton-Labs/terraform-module-testing/[email protected]
with:
tf_path: tests/pass-multi

- name: Initialize - Pass - Multi - Condition Delayed
id: init-pass-multi-condition-delayed
uses: Invicton-Labs/terraform-module-testing/[email protected]
with:
tf_path: tests/pass-multi-condition-delayed
- name: Run Tests - Pass - Multi - Condition Delayed
id: tests-pass-multi-condition-delayed
uses: Invicton-Labs/terraform-module-testing/[email protected]
with:
tf_path: tests/pass-multi-condition-delayed

- name: Initialize - Pass - Multi - Message Delayed
id: init-pass-multi-message-delayed
uses: Invicton-Labs/terraform-module-testing/[email protected]
with:
tf_path: tests/pass-multi-message-delayed
- name: Run Tests - Pass - Multi - Message Delayed
id: tests-pass-multi-message-delayed
uses: Invicton-Labs/terraform-module-testing/[email protected]
with:
tf_path: tests/pass-multi-message-delayed

- name: Initialize - Pass - Multi - Condition and Message Delayed
id: init-pass-multi-condition-message-delayed
uses: Invicton-Labs/terraform-module-testing/[email protected]
with:
tf_path: tests/pass-multi-condition-message-delayed
- name: Run Tests - Pass - Multi - Condition and Message Delayed
id: tests-pass-multi-condition-message-delayed
uses: Invicton-Labs/terraform-module-testing/[email protected]
with:
tf_path: tests/pass-multi-condition-message-delayed

- name: Initialize - Fail
id: init-fail
Expand Down Expand Up @@ -143,6 +187,42 @@ jobs:
tf_path: tests/fail-condition-message-delayed
stderr_contains: sample error

- name: Initialize - Fail - Multi - Condition Delayed
id: init-fail-multi-condition-delayed
uses: Invicton-Labs/terraform-module-testing/[email protected]
with:
tf_path: tests/fail-multi-condition-delayed
- name: Run Tests - Fail - Multi - Condition Delayed
id: tests-fail-multi-condition-delayed
uses: Invicton-Labs/terraform-module-testing/[email protected]
with:
tf_path: tests/fail-multi-condition-delayed
stderr_contains: sample error

- name: Initialize - Fail - Multi - Message Delayed
id: init-fail-multi-message-delayed
uses: Invicton-Labs/terraform-module-testing/[email protected]
with:
tf_path: tests/fail-multi-message-delayed
- name: Run Tests - Fail - Multi - Message Delayed
id: tests-fail-multi-message-delayed
uses: Invicton-Labs/terraform-module-testing/[email protected]
with:
tf_path: tests/fail-multi-message-delayed
stderr_contains: sample error

- name: Initialize - Fail - Multi - Condition and Message Delayed
id: init-fail-multi-condition-message-delayed
uses: Invicton-Labs/terraform-module-testing/[email protected]
with:
tf_path: tests/fail-multi-condition-message-delayed
- name: Run Tests - Fail - Multi - Condition and Message Delayed
id: tests-fail-multi-condition-message-delayed
uses: Invicton-Labs/terraform-module-testing/[email protected]
with:
tf_path: tests/fail-multi-condition-message-delayed
stderr_contains: sample error

# This job just waits for all other jobs to pass. We have it here
# so our branch protection rule can reference a single job, instead
# of needing to list every matrix value of every job above.
Expand Down
11 changes: 11 additions & 0 deletions outputs.tf
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//==================================================
// Outputs that match the input variables
//==================================================
output "error_message" {
description = "The value of the `error_message` input variable."
value = var.error_message
Expand All @@ -8,6 +11,14 @@ output "condition" {
value = var.condition
}

output "assertions" {
description = "The value of the `assertions` input variable."
value = var.assertions
}

//==================================================
// Outputs generated by this module
//==================================================
output "checked" {
description = "Whether the condition has been checked (used for assertion dependencies)."
value = var.condition == true ? true : true
Expand Down
13 changes: 13 additions & 0 deletions tests/fail-multi-condition-delayed/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module "fail_multi_condition_delayed" {
source = "../../"
assertions = [
{
condition = uuid() == ""
error_message = "sample error"
},
{
condition = uuid() == ""
error_message = "sample error"
}
]
}
13 changes: 13 additions & 0 deletions tests/fail-multi-condition-message-delayed/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module "fail_multi_condition_message_delayed" {
source = "../../"
assertions = [
{
condition = uuid() == ""
error_message = "sample error: ${uuid()}"
},
{
condition = uuid() == ""
error_message = "sample error: ${uuid()}"
}
]
}
13 changes: 13 additions & 0 deletions tests/fail-multi-message-delayed/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module "fail_multi_message_delayed" {
source = "../../"
assertions = [
{
condition = false
error_message = "sample error: ${uuid()}"
},
{
condition = false
error_message = "sample error: ${uuid()}"
}
]
}
13 changes: 13 additions & 0 deletions tests/fail-multi/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module "fail_multi" {
source = "../../"
assertions = [
{
condition = false
error_message = "sample error"
},
{
condition = false
error_message = "sample error"
}
]
}
13 changes: 13 additions & 0 deletions tests/pass-multi-condition-delayed/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module "pass_multi_condition_delayed" {
source = "../../"
assertions = [
{
condition = uuid() != ""
error_message = "sample error"
},
{
condition = uuid() != ""
error_message = "sample error"
}
]
}
13 changes: 13 additions & 0 deletions tests/pass-multi-condition-message-delayed/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module "pass_multi_condition_message_delayed" {
source = "../../"
assertions = [
{
condition = uuid() != ""
error_message = "sample error: ${uuid()}"
},
{
condition = uuid() != ""
error_message = "sample error: ${uuid()}"
}
]
}
13 changes: 13 additions & 0 deletions tests/pass-multi-message-delayed/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module "pass_multi_message_delayed" {
source = "../../"
assertions = [
{
condition = true
error_message = "sample error: ${uuid()}"
},
{
condition = true
error_message = "sample error: ${uuid()}"
}
]
}
13 changes: 13 additions & 0 deletions tests/pass-multi/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module "pass_multi" {
source = "../../"
assertions = [
{
condition = true
error_message = "Not needed!"
},
{
condition = true
error_message = "Not needed!"
}
]
}
65 changes: 61 additions & 4 deletions variables.tf
Original file line number Diff line number Diff line change
@@ -1,18 +1,75 @@
variable "error_message" {
description = "The error message to display if the condition evaluates to `false`."
type = string
nullable = false
nullable = true
default = null
}

variable "condition" {
description = "The condition to ensure is `true`."
type = bool
nullable = true
default = null
validation {
// We have to use var.error_message != null to force the evaluation to wait
// We have to use var.error_message == "" to force the evaluation to wait
// until var.error_message is known. Otherwise, it can fail during the validation
// phase but won't output the proper error message.
// https://github.com/hashicorp/terraform/issues/35397
condition = var.error_message == "" ? var.condition : var.condition
error_message = var.error_message
condition = var.condition == null ? true : (var.error_message == null ? true : (var.error_message == "" ? var.condition : var.condition))
error_message = var.condition == null ? "" : (
var.condition ? "" : (
var.error_message == null ? "" : "ASSERTION FAILURE: ${var.error_message}"
)
)
}
}

variable "assertions" {
description = "A list of conditions and error message pairs to check. This is for use when you want to make multiple assertions with a single instance of this module."
type = list(object({
condition = bool
error_message = string
}))
default = null
nullable = true

// Verify that either the single assertion variables are used, or this variable is used. Not both.
validation {
// Ternaries allow lazy evaluation, which reduces the chance that a value
// not known at plan time will force this validation to wait for apply time.
condition = (
var.condition == null ? (
var.error_message == null ? var.assertions != null : false
) : false
) ? true : (
var.condition != null ? (
var.error_message != null ? var.assertions == null : false
) : false
)
error_message = "Either the `condition` and `error_message` variables must be provided and the `assertions` variable must be `null`, or the `assertions` variable must be provided and the `condition` and `error_message` variables must be `null`. To check a single assertion, use `condition` and `error_message`; to check multiple assertions, use `assertions`."
}

// Check that either there is no assertions list, or if there is,
// none of the conditions in it are false.
validation {
// We pass this validation if `condition` or `error_message` are not null,
// so it throws the validation error about multiple vars being provided instead
// of actually checking the assertions in this variable.
condition = var.condition != null ? true : (
var.error_message != null ? true : (
var.assertions == null ? true : (
length([
for v in var.assertions :
false
if !v.condition
]) == 0
)
)
)
error_message = var.assertions == null ? "" : join("\n\n", [
for v in var.assertions :
"ASSERTION FAILURE: ${v.error_message}"
if !v.condition
])
}
}

0 comments on commit f98059f

Please sign in to comment.