How to access provider config when acceptance testing?

I’m following the scaffolding example using the plugin framework and want to access my API client inside my provider so I can verify that my resources actually exist in the backend. My client is created using config in the provider definition. Is there a way of getting the provider config so I can use the instantiated client? Or do I need to manually create it using hardcoded variables that match what I’m setting in my config?

type MyClientConfiguration struct {
    MyClient SomeApiClient
}


func (p *ScaffoldingProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
    var data ScaffoldingProviderModel

    resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)

    if resp.Diagnostics.HasError() {
        return
    }


    // Example client configuration for data sources and resources
    client := MyClientConfiguration {
        // build MyClient using configuration from TF, including endpoint and auth token etc
    }
    resp.DataSourceData = client
    resp.ResourceData = client
}

My test:

var testAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){
    "scaffolding": providerserver.NewProtocol6WithError(New("test")()),
}

func TestAccExampleResource(t *testing.T) {
    const config = `
provider "scaffolding" {
    endpoint = "http://example.com/api/foo
}

resource "scaffolding_example" "test" {
  configurable_attribute = "foo"
}
`


    resource.Test(t, resource.TestCase{
        ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
        Steps: []resource.TestStep{
            // Create and Read testing
            {
                Config: config,
                Check: resource.ComposeAggregateTestCheckFunc(
                    testAccExampleResourceActuallyCreated("scaffolding_example.test"),
                    ... other tests here ...
                ),
            },
            // Delete testing automatically occurs in TestCase
        },
    })
}


func testAccExampleResourceActuallyCreated(resourceName string) resource.TestCheckFunc {
  return func(s *terraform.State) error {
    // retrieve the resource by name from state
    rs, ok := s.RootModule().Resources[resourceName]
    if !ok {
      return fmt.Errorf("Not found: %s", resourceName)
    }

    if rs.Primary.ID == "" {
      return fmt.Errorf("Resource ID is not set")
    }

    // How do we get the provider config to recreate a client, or otherwise get the client from the provider?

    // now use the client to query the backend API to see if our resource exists
    ...
  }
}

How do I instantiate an API client using the same values that were used in the config?

The acceptance test framework will automatically run your Read() method and compare the resulting state against your test values, so you’re already testing whether the resource gets created.

The pattern for an single resource.TestStep is something like:

  • Create() (step0)
  • State is compared (step0)
  • Read() (step0)
  • State is compared (step0)
  • Delete()

Two resource.TestSteps will look like:

  • Create() (step0)
  • State is compared (step0)
  • Read() (step0)
  • State is compared (step0)
  • Read() (part of planning)
  • Update() (step1)
  • State is compared (step1)
  • Read() (step1)
  • State is compared (step1)
  • Delete()
1 Like

Thank you very much, that was an exceptionally clear and helpful response!

1 Like