Plugin-framework provider covering projects, environments, applications, Compose stacks, managed databases, domains, mounts, ports, redirects, basic auth, registries, SSH keys, certificates and backup destinations, over Dokploy's tRPC-over-REST API. The shim package exposes the provider to other Go modules, which is how pulumi-dokploy bridges it.
232 lines
6.7 KiB
Markdown
232 lines
6.7 KiB
Markdown
# State Checks and Plan Checks Reference
|
|
|
|
Detailed reference for `statecheck` and `plancheck` packages from
|
|
`terraform-plugin-testing`. Read this when writing assertions for test steps.
|
|
|
|
Source: [State Checks](https://developer.hashicorp.com/terraform/plugin/testing/acceptance-tests/state-checks/resource),
|
|
[Plan Checks](https://developer.hashicorp.com/terraform/plugin/testing/acceptance-tests/plan-checks)
|
|
|
|
---
|
|
|
|
## Table of Contents
|
|
|
|
1. [State Checks](#state-checks)
|
|
2. [Known Value Types](#known-value-types)
|
|
3. [tfjsonpath Navigation](#tfjsonpath-navigation)
|
|
4. [Value Comparers](#value-comparers)
|
|
5. [Plan Checks](#plan-checks)
|
|
|
|
---
|
|
|
|
## State Checks
|
|
|
|
Use via `ConfigStateChecks` field on `TestStep`. All assertion errors are
|
|
aggregated and reported together.
|
|
|
|
### ExpectKnownValue
|
|
|
|
Assert an attribute has a specific type and value:
|
|
|
|
```go
|
|
statecheck.ExpectKnownValue("example_widget.test",
|
|
tfjsonpath.New("name"),
|
|
knownvalue.StringExact("my-widget"))
|
|
```
|
|
|
|
### ExpectSensitiveValue
|
|
|
|
Assert an attribute is marked sensitive (requires Terraform 1.4.6+):
|
|
|
|
```go
|
|
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
|
|
tfversion.SkipBelow(tfversion.Version1_4_6),
|
|
},
|
|
// ...
|
|
statecheck.ExpectSensitiveValue("example_widget.test",
|
|
tfjsonpath.New("api_key"))
|
|
```
|
|
|
|
### CompareValue
|
|
|
|
Compare the same attribute across sequential test steps:
|
|
|
|
```go
|
|
compareValuesSame := statecheck.CompareValue(compare.ValuesSame())
|
|
|
|
Steps: []resource.TestStep{
|
|
{
|
|
Config: testAccConfig_v1(rName),
|
|
ConfigStateChecks: []statecheck.StateCheck{
|
|
compareValuesSame.AddStateValue("example_widget.test",
|
|
tfjsonpath.New("id")),
|
|
},
|
|
},
|
|
{
|
|
Config: testAccConfig_v2(rName),
|
|
ConfigStateChecks: []statecheck.StateCheck{
|
|
compareValuesSame.AddStateValue("example_widget.test",
|
|
tfjsonpath.New("id")),
|
|
},
|
|
},
|
|
},
|
|
```
|
|
|
|
### CompareValuePairs
|
|
|
|
Compare attributes between two resources:
|
|
|
|
```go
|
|
statecheck.CompareValuePairs(
|
|
"example_widget.test", tfjsonpath.New("vpc_id"),
|
|
"example_vpc.test", tfjsonpath.New("id"),
|
|
compare.ValuesSame())
|
|
```
|
|
|
|
### CompareValueCollection
|
|
|
|
Check if a value exists in a collection attribute:
|
|
|
|
```go
|
|
statecheck.CompareValueCollection(
|
|
"example_widget.test", tfjsonpath.New("tags"),
|
|
"example_widget.test", tfjsonpath.New("name"),
|
|
compare.ValuesSame())
|
|
```
|
|
|
|
---
|
|
|
|
## Known Value Types
|
|
|
|
Use with `ExpectKnownValue` to assert attribute values:
|
|
|
|
| Type | Example |
|
|
|------|---------|
|
|
| `knownvalue.StringExact("value")` | Exact string match |
|
|
| `knownvalue.StringRegexp(regexp.MustCompile(`^arn:`))` | Regex match |
|
|
| `knownvalue.Bool(true)` | Boolean value |
|
|
| `knownvalue.Int64Exact(42)` | Exact int64 |
|
|
| `knownvalue.Float64Exact(3.14)` | Exact float64 |
|
|
| `knownvalue.NotNull()` | Value is set (not null) |
|
|
| `knownvalue.Null()` | Value is null |
|
|
| `knownvalue.ListExact([]knownvalue.Check{...})` | Exact list match |
|
|
| `knownvalue.ListPartial(map[int]knownvalue.Check{0: ...})` | Partial list match |
|
|
| `knownvalue.ListSizeExact(3)` | List has N elements |
|
|
| `knownvalue.SetExact([]knownvalue.Check{...})` | Exact set match |
|
|
| `knownvalue.SetPartial([]knownvalue.Check{...})` | Set contains items |
|
|
| `knownvalue.SetSizeExact(2)` | Set has N elements |
|
|
| `knownvalue.MapExact(map[string]knownvalue.Check{...})` | Exact map match |
|
|
| `knownvalue.MapPartial(map[string]knownvalue.Check{...})` | Map contains keys |
|
|
| `knownvalue.MapSizeExact(1)` | Map has N keys |
|
|
| `knownvalue.ObjectExact(map[string]knownvalue.Check{...})` | Exact object match |
|
|
| `knownvalue.ObjectPartial(map[string]knownvalue.Check{...})` | Object has attributes |
|
|
| `knownvalue.Float32Exact(1.5)` | Exact float32 |
|
|
| `knownvalue.Int32Exact(42)` | Exact int32 |
|
|
| `knownvalue.NumberExact(big.NewFloat(42))` | Exact number (`*big.Float`) |
|
|
| `knownvalue.TupleExact([]knownvalue.Check{...})` | Exact tuple match |
|
|
| `knownvalue.TuplePartial(map[int]knownvalue.Check{0: ...})` | Partial tuple match |
|
|
| `knownvalue.TupleSizeExact(3)` | Tuple has N elements |
|
|
|
|
### Nested Value Example
|
|
|
|
```go
|
|
statecheck.ExpectKnownValue("example_widget.test",
|
|
tfjsonpath.New("settings"),
|
|
knownvalue.ObjectExact(map[string]knownvalue.Check{
|
|
"mode": knownvalue.StringExact("production"),
|
|
"enabled": knownvalue.Bool(true),
|
|
}))
|
|
```
|
|
|
|
---
|
|
|
|
## tfjsonpath Navigation
|
|
|
|
Navigate nested attributes in state:
|
|
|
|
```go
|
|
tfjsonpath.New("attribute") // top-level attribute
|
|
tfjsonpath.New("block").AtMapKey("key") // nested map/object key
|
|
tfjsonpath.New("list_attr").AtSliceIndex(0) // list element by index
|
|
tfjsonpath.New("block").AtMapKey("nested").AtMapKey("deep") // deep nesting
|
|
```
|
|
|
|
---
|
|
|
|
## Value Comparers
|
|
|
|
Use with `CompareValue`, `CompareValuePairs`, `CompareValueCollection`:
|
|
|
|
| Comparer | Purpose |
|
|
|----------|---------|
|
|
| `compare.ValuesSame()` | Values are identical |
|
|
| `compare.ValuesDiffer()` | Values are different |
|
|
|
|
---
|
|
|
|
## Plan Checks
|
|
|
|
Use via `ConfigPlanChecks` or `RefreshPlanChecks` on `TestStep`. Plan checks
|
|
inspect the plan file at specific phases.
|
|
|
|
### ConfigPlanChecks Phases
|
|
|
|
```go
|
|
ConfigPlanChecks: resource.ConfigPlanChecks{
|
|
PreApply: []plancheck.PlanCheck{...}, // after plan, before apply
|
|
PostApplyPreRefresh: []plancheck.PlanCheck{...}, // after apply, before refresh
|
|
PostApplyPostRefresh: []plancheck.PlanCheck{...}, // after refresh
|
|
},
|
|
```
|
|
|
|
### Built-in Plan Checks
|
|
|
|
```go
|
|
// Expect no changes in plan
|
|
plancheck.ExpectEmptyPlan()
|
|
|
|
// Expect changes in plan
|
|
plancheck.ExpectNonEmptyPlan()
|
|
|
|
// Expect specific resource action
|
|
plancheck.ExpectResourceAction("example_widget.test", plancheck.ResourceActionCreate)
|
|
plancheck.ExpectResourceAction("example_widget.test", plancheck.ResourceActionUpdate)
|
|
plancheck.ExpectResourceAction("example_widget.test", plancheck.ResourceActionDestroy)
|
|
plancheck.ExpectResourceAction("example_widget.test", plancheck.ResourceActionNoop)
|
|
|
|
// Expect known plan value
|
|
plancheck.ExpectKnownValue("example_widget.test",
|
|
tfjsonpath.New("name"),
|
|
knownvalue.StringExact("my-widget"))
|
|
|
|
// Expect unknown (computed) value in plan
|
|
plancheck.ExpectUnknownValue("example_widget.test",
|
|
tfjsonpath.New("computed_field"))
|
|
|
|
// Expect sensitive value in plan
|
|
plancheck.ExpectSensitiveValue("example_widget.test",
|
|
tfjsonpath.New("api_key"))
|
|
```
|
|
|
|
### No-Op After Update Example
|
|
|
|
Verify that updating a config back to original values produces no diff:
|
|
|
|
```go
|
|
Steps: []resource.TestStep{
|
|
{
|
|
Config: testAccConfig_basic(rName),
|
|
},
|
|
{
|
|
Config: testAccConfig_updated(rName),
|
|
},
|
|
{
|
|
Config: testAccConfig_basic(rName),
|
|
ConfigPlanChecks: resource.ConfigPlanChecks{
|
|
PreApply: []plancheck.PlanCheck{
|
|
plancheck.ExpectEmptyPlan(),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
```
|