How to write a Terraform test that uses a non-Hashicorp provider?

Hello,

I’m trying to write a Terraform test (using the terraform test command) using the Cloudflare provider.

I have something very simple like this:

provider "cloudflare" {
  api_token = var.cloudflare_api_token
}

run "create" {
  variables {
    name       = "foobar"
    endpoint = "127.0.0.1"
  }

  module {
    source = "./"
  }

  command = apply

  assert {
    ...
  }
}

But the terraform init phase fails with:

╷
│ Error: Failed to query available provider packages
│ 
│ Could not retrieve the list of available versions for provider hashicorp/cloudflare: provider registry registry.terraform.io does not have a provider named registry.terraform.io/hashicorp/cloudflare
│ 
│ Did you intend to use cloudflare/cloudflare? If so, you must specify that source address in each module which requires that provider. To see which modules are currently depending on hashicorp/cloudflare, run the following command:
│     terraform providers

Using the mentioned terraform providers command, I can see that the misconfigured provider is for my test.tests.dns-records resource (which is the top-level resource I’m trying to configure, with the API token that connect to a test Cloudflare account).

The Terraform Test documentation doesn’t mention how to configure provider sources in a test. How is it possible to say that the cloudflare provider in the test is actually a cloudflare/cloudflare provider and not a hashicorp/cloudflare provider?

Thanks!

1 Like

Hi @multani,

A test scenario configuration (that is, a .tftest.hcl file) is treated by Terraform as an extension of the module it belongs to, and so expressions and other references in the test scenario are resolved in the context of the associated module.

Your provider "cloudflare" block is therefore treated as if it were written inside one of the module’s .tf files, replacing any provider "cloudflare" blocks that were already present. The meaning of the label "cloudflare" is defined by the module itself.

With all of that said then, I would expect this to work if you include a required_providers block in the module you are testing (that is, in one of your .tf files, not in the .tftest.hcl file), which specifies the global source address for that local name:

terraform {
  required_providers {
    cloudflare = {
      source = "cloudflare/cloudflare"
    }
  }
}

Since your test scenario specifies a different module to use as the root module for the test, you’ll need to make sure that module specifies what "cloudflare" is intended to mean using the syntax above, and also make sure that any other modules in your configuration have agreeing declarations.

1 Like

Hi @apparentlymart,

So, all my modules have the required_providers block correctly configured, as you proposed. These modules are expected to be called from a Terraform workspace, where the provider has been correctly initialized. This is working fine for the normal “non test” setup.
However, during my tests, I’d like to use a specific provider configuration: in my scenario, I’d like to connect to a specific Cloudflare account, that exists only for testing purpose.

In any case, with any other provider, it would be the same problem: in order to run my tests, I’d like to configure my provider(s) with specific settings that are tests-specific. I still don’t know how this could be achieved at the moment.
Some providers (like Cloudflare, actually) can be configured via environment variables, so I would need to export the specific environment variables before running the tests, but this really depends on how each providers are implemented. Although that may work, this is also not ideal for me:

  1. In our setup, all our providers are explicitly configured (at least, specific parts of them) via the provider configuration parameters. Using environment variables would deviate a bit from our common setup.
  2. Using environment variables “hide” the configuration and could create potential problems where the ambient credentials are used without being explicitly specified.

In the original issue, I mentioned “non-Hashicorp provider” ; we are, for instance, using the Google provider this way:

provider "google" {
  project = var.google_project_id
}

And the project ID setting is supposed to be explicitly configured somewhere (in a .auto.tfvars file, in our case) before starting the tests, otherwise the tests are failing. This forces our developers to be explicit on which Google Cloud project the tests are going to be run against (while still picking the ambient credentials).
For this Google provider, this works as provider "google" resolves always to hashicorp/google, but this is a specific scenario for the providers available directly in the hashicorp/* namespace, I believe.

Is there another way to configure providers in a test-specific way?