Files
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

5.9 KiB

Ephemeral Resource Testing Reference

Testing patterns for ephemeral resources using terraform-plugin-testing. Ephemeral resources reference external data without persisting it to plan or state artifacts, which means standard plan checks and state checks cannot directly assert on ephemeral resource data.

Source: Ephemeral Resource Acceptance Tests

Requires Terraform >= 1.10.0 — gate all ephemeral tests with tfversion.SkipBelow(tfversion.Version1_10_0).


Table of Contents

  1. Testing Approaches
  2. Direct Integration Testing
  3. Echo Provider Pattern
  4. Multi-Step Testing

Testing Approaches

Two strategies for testing ephemeral resources:

Approach When to use
Direct integration Verify the ephemeral resource successfully provides data to a dependent resource or provider
Echo provider Assert on specific attribute values using ConfigStateChecks via the echoprovider package

Direct Integration Testing

Test that an ephemeral resource successfully provides data to a dependent resource. No direct assertions on ephemeral data — the test passes if the dependent resource applies cleanly.

func TestExampleCloudSecret_DnsKerberos(t *testing.T) {
    resource.UnitTest(t, resource.TestCase{
        TerraformVersionChecks: []tfversion.TerraformVersionCheck{
            tfversion.SkipBelow(tfversion.Version1_10_0),
        },
        ExternalProviders: map[string]resource.ExternalProvider{
            "dns": {
                Source: "hashicorp/dns",
            },
        },
        ProtoV5ProviderFactories: map[string]func() (tfprotov5.ProviderServer, error){
            "examplecloud": providerserver.NewProtocol5WithError(New()),
        },
        Steps: []resource.TestStep{
            {
                Config: `
ephemeral "examplecloud_secret" "krb" {
  name = "example_kerberos_user"
}

provider "dns" {
  update {
    server = "ns.example.com"
    gssapi {
      realm    = ephemeral.examplecloud_secret.krb.secret_data.realm
      username = ephemeral.examplecloud_secret.krb.secret_data.username
      password = ephemeral.examplecloud_secret.krb.secret_data.password
    }
  }
}

resource "dns_a_record_set" "record_set" {
  zone = "example.com."
  addresses = ["192.168.0.1", "192.168.0.2", "192.168.0.3"]
}
                `,
            },
        },
    })
}

Echo Provider Pattern

The echoprovider package (Protocol V6) captures ephemeral data into a managed resource's state, making it assertable with standard ConfigStateChecks.

Setup

Register both your provider and the echo provider:

import (
    "github.com/hashicorp/terraform-plugin-testing/echoprovider"
)

func TestExampleCloudSecret(t *testing.T) {
    resource.UnitTest(t, resource.TestCase{
        TerraformVersionChecks: []tfversion.TerraformVersionCheck{
            tfversion.SkipBelow(tfversion.Version1_10_0),
        },
        ProtoV5ProviderFactories: map[string]func() (tfprotov5.ProviderServer, error){
            "examplecloud": providerserver.NewProtocol5WithError(New()),
        },
        ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
            "echo": echoprovider.NewProviderServer(),
        },
        Steps: []resource.TestStep{
            // test configurations
        },
    })
}

Config Pattern

Pass ephemeral data to the echo provider's data attribute, then assert on the echo managed resource:

ephemeral "examplecloud_secret" "krb" {
  name = "example_kerberos_user"
}

provider "echo" {
  data = ephemeral.examplecloud_secret.krb.secret_data
}

resource "echo" "test_krb" {}

State Assertions

Assert on the echo resource's data attribute using standard state checks:

Steps: []resource.TestStep{
    {
        Config: `...`,
        ConfigStateChecks: []statecheck.StateCheck{
            statecheck.ExpectKnownValue("echo.test_krb",
                tfjsonpath.New("data").AtMapKey("realm"),
                knownvalue.StringExact("EXAMPLE.COM")),
            statecheck.ExpectKnownValue("echo.test_krb",
                tfjsonpath.New("data").AtMapKey("username"),
                knownvalue.StringExact("john-doe")),
            statecheck.ExpectKnownValue("echo.test_krb",
                tfjsonpath.New("data").AtMapKey("password"),
                knownvalue.StringRegexp(regexp.MustCompile(`^.{12}$`))),
        },
    },
},

Multi-Step Testing

The echo resource has special behavior to accommodate ephemeral data variability:

  • During planning for new resources, the data attribute is marked unknown
  • Existing echo resources preserve prior state regardless of config changes
  • Refresh operations always return prior state

Because of this, create new echo resource instances for each test step rather than reusing the same one:

Steps: []resource.TestStep{
    {
        Config: `
ephemeral "examplecloud_secret" "krb" {
  name = "user_one"
}
provider "echo" {
  data = ephemeral.examplecloud_secret.krb
}
resource "echo" "test_krb_one" {}
        `,
        ConfigStateChecks: []statecheck.StateCheck{
            statecheck.ExpectKnownValue("echo.test_krb_one",
                tfjsonpath.New("data").AtMapKey("name"),
                knownvalue.StringExact("user_one")),
        },
    },
    {
        Config: `
ephemeral "examplecloud_secret" "krb" {
  name = "user_two"
}
provider "echo" {
  data = ephemeral.examplecloud_secret.krb
}
resource "echo" "test_krb_two" {}
        `,
        ConfigStateChecks: []statecheck.StateCheck{
            statecheck.ExpectKnownValue("echo.test_krb_two",
                tfjsonpath.New("data").AtMapKey("name"),
                knownvalue.StringExact("user_two")),
        },
    },
},