Files
terraform-provider-dokploy/.agents/skills/provider-test-patterns/references/checks.md
Max Vojtkov a6d8aa8b52 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.
2026-08-09 12:17:26 +03:00

6.7 KiB

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, Plan Checks


Table of Contents

  1. State Checks
  2. Known Value Types
  3. tfjsonpath Navigation
  4. Value Comparers
  5. 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:

statecheck.ExpectKnownValue("example_widget.test",
    tfjsonpath.New("name"),
    knownvalue.StringExact("my-widget"))

ExpectSensitiveValue

Assert an attribute is marked sensitive (requires Terraform 1.4.6+):

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:

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:

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:

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

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:

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

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

// 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:

Steps: []resource.TestStep{
    {
        Config: testAccConfig_basic(rName),
    },
    {
        Config: testAccConfig_updated(rName),
    },
    {
        Config: testAccConfig_basic(rName),
        ConfigPlanChecks: resource.ConfigPlanChecks{
            PreApply: []plancheck.PlanCheck{
                plancheck.ExpectEmptyPlan(),
            },
        },
    },
},