A Terraform provider for Dokploy
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.
This commit is contained in:
231
.agents/skills/provider-test-patterns/references/checks.md
Normal file
231
.agents/skills/provider-test-patterns/references/checks.md
Normal file
@@ -0,0 +1,231 @@
|
||||
# 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(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
```
|
||||
Reference in New Issue
Block a user