mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-23 07:33:32 -06:00
Allow unconfigured provider functions in test context (#1603)
Signed-off-by: Christian Mesh <christianmesh1@gmail.com>
This commit is contained in:
parent
08469452b6
commit
015b79b139
@ -12,6 +12,7 @@ BUG FIXES:
|
||||
* Fix inmem backend crash due to missing struct field ([#1619](https://github.com/opentofu/opentofu/pull/1619))
|
||||
* Added a check in the `tofu test` to validate that the names of test run blocks do not contain spaces. ([#1489](https://github.com/opentofu/opentofu/pull/1489))
|
||||
* `tofu test` now supports accessing module outputs when the module has no resources. ([#1409](https://github.com/opentofu/opentofu/pull/1409))
|
||||
* Fixed support for provider functions in tests ([#1603](https://github.com/opentofu/opentofu/pull/1603))
|
||||
|
||||
## Previous Releases
|
||||
|
||||
|
@ -15,7 +15,7 @@ import (
|
||||
|
||||
// This builds a provider function using an EvalContext and some additional information
|
||||
// This is split out of BuiltinEvalContext for testing
|
||||
func evalContextProviderFunction(ctx EvalContext, mc *configs.Config, op walkOperation, pf addrs.ProviderFunction, rng tfdiags.SourceRange) (*function.Function, tfdiags.Diagnostics) {
|
||||
func evalContextProviderFunction(providers func(addrs.AbsProviderConfig) providers.Interface, mc *configs.Config, op walkOperation, pf addrs.ProviderFunction, rng tfdiags.SourceRange) (*function.Function, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
pr, ok := mc.Module.ProviderRequirements.RequiredProviders[pf.ProviderName]
|
||||
@ -35,7 +35,7 @@ func evalContextProviderFunction(ctx EvalContext, mc *configs.Config, op walkOpe
|
||||
Alias: pf.ProviderAlias,
|
||||
}
|
||||
|
||||
provider := ctx.Provider(absPc)
|
||||
provider := providers(absPc)
|
||||
|
||||
if provider == nil {
|
||||
// Configured provider (NodeApplyableProvider) not required via transform_provider.go. Instead we should use the unconfigured instance (NodeEvalableProvider) in the root.
|
||||
@ -59,7 +59,7 @@ func evalContextProviderFunction(ctx EvalContext, mc *configs.Config, op walkOpe
|
||||
}
|
||||
}
|
||||
|
||||
provider = ctx.Provider(addrs.AbsProviderConfig{Provider: pr.Type})
|
||||
provider = providers(addrs.AbsProviderConfig{Provider: pr.Type})
|
||||
if provider == nil {
|
||||
// This should not be possible
|
||||
return nil, diags.Append(&hcl.Diagnostic{
|
||||
|
@ -134,7 +134,7 @@ func TestFunctions(t *testing.T) {
|
||||
}
|
||||
|
||||
// Provider missing
|
||||
_, diags := evalContextProviderFunction(mockCtx, cfg, walkValidate, providerFunc("provider::invalid::unknown"), rng)
|
||||
_, diags := evalContextProviderFunction(mockCtx.Provider, cfg, walkValidate, providerFunc("provider::invalid::unknown"), rng)
|
||||
if !diags.HasErrors() {
|
||||
t.Fatal("expected unknown function provider")
|
||||
}
|
||||
@ -143,7 +143,7 @@ func TestFunctions(t *testing.T) {
|
||||
}
|
||||
|
||||
// Provider not initialized
|
||||
_, diags = evalContextProviderFunction(mockCtx, cfg, walkValidate, providerFunc("provider::mockname::missing"), rng)
|
||||
_, diags = evalContextProviderFunction(mockCtx.Provider, cfg, walkValidate, providerFunc("provider::mockname::missing"), rng)
|
||||
if !diags.HasErrors() {
|
||||
t.Fatal("expected unknown function provider")
|
||||
}
|
||||
@ -156,7 +156,7 @@ func TestFunctions(t *testing.T) {
|
||||
|
||||
// Function missing (validate)
|
||||
mockProvider.GetFunctionsCalled = false
|
||||
_, diags = evalContextProviderFunction(mockCtx, cfg, walkValidate, providerFunc("provider::mockname::missing"), rng)
|
||||
_, diags = evalContextProviderFunction(mockCtx.Provider, cfg, walkValidate, providerFunc("provider::mockname::missing"), rng)
|
||||
if diags.HasErrors() {
|
||||
t.Fatal(diags.Err())
|
||||
}
|
||||
@ -166,7 +166,7 @@ func TestFunctions(t *testing.T) {
|
||||
|
||||
// Function missing (Non-validate)
|
||||
mockProvider.GetFunctionsCalled = false
|
||||
_, diags = evalContextProviderFunction(mockCtx, cfg, walkPlan, providerFunc("provider::mockname::missing"), rng)
|
||||
_, diags = evalContextProviderFunction(mockCtx.Provider, cfg, walkPlan, providerFunc("provider::mockname::missing"), rng)
|
||||
if !diags.HasErrors() {
|
||||
t.Fatal("expected unknown function")
|
||||
}
|
||||
@ -188,7 +188,7 @@ func TestFunctions(t *testing.T) {
|
||||
// Load functions into ctx
|
||||
for _, fn := range []string{"echo", "concat", "coalesce", "unknown_param", "error_param"} {
|
||||
pf := providerFunc("provider::mockname::" + fn)
|
||||
impl, diags := evalContextProviderFunction(mockCtx, cfg, walkPlan, pf, rng)
|
||||
impl, diags := evalContextProviderFunction(mockCtx.Provider, cfg, walkPlan, pf, rng)
|
||||
if diags.HasErrors() {
|
||||
t.Fatal(diags.Err())
|
||||
}
|
||||
|
@ -526,7 +526,7 @@ func (ctx *BuiltinEvalContext) EvaluationScope(self addrs.Referenceable, source
|
||||
}
|
||||
|
||||
scope := ctx.Evaluator.Scope(data, self, source, func(pf addrs.ProviderFunction, rng tfdiags.SourceRange) (*function.Function, tfdiags.Diagnostics) {
|
||||
return evalContextProviderFunction(ctx, mc, ctx.Evaluator.Operation, pf, rng)
|
||||
return evalContextProviderFunction(ctx.Provider, mc, ctx.Evaluator.Operation, pf, rng)
|
||||
})
|
||||
scope.SetActiveExperiments(mc.Module.ActiveExperiments)
|
||||
|
||||
|
@ -7,17 +7,20 @@ package tofu
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
"github.com/zclconf/go-cty/cty/convert"
|
||||
"github.com/zclconf/go-cty/cty/function"
|
||||
|
||||
"github.com/opentofu/opentofu/internal/addrs"
|
||||
"github.com/opentofu/opentofu/internal/configs"
|
||||
"github.com/opentofu/opentofu/internal/lang"
|
||||
"github.com/opentofu/opentofu/internal/moduletest"
|
||||
"github.com/opentofu/opentofu/internal/plans"
|
||||
"github.com/opentofu/opentofu/internal/providers"
|
||||
"github.com/opentofu/opentofu/internal/states"
|
||||
"github.com/opentofu/opentofu/internal/tfdiags"
|
||||
)
|
||||
@ -99,11 +102,50 @@ func (ctx *TestContext) evaluate(state *states.SyncState, changes *plans.Changes
|
||||
Operation: operation,
|
||||
}
|
||||
|
||||
var providerInstanceLock sync.Mutex
|
||||
providerInstances := make(map[addrs.Provider]providers.Interface)
|
||||
defer func() {
|
||||
for addr, inst := range providerInstances {
|
||||
log.Printf("[INFO] Shutting down test provider %s", addr)
|
||||
inst.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
providerSupplier := func(addr addrs.AbsProviderConfig) providers.Interface {
|
||||
providerInstanceLock.Lock()
|
||||
defer providerInstanceLock.Unlock()
|
||||
|
||||
if inst, ok := providerInstances[addr.Provider]; ok {
|
||||
return inst
|
||||
}
|
||||
|
||||
factory, ok := ctx.plugins.providerFactories[addr.Provider]
|
||||
if !ok {
|
||||
log.Printf("[WARN] Unable to find provider %s in test context", addr)
|
||||
providerInstances[addr.Provider] = nil
|
||||
return nil
|
||||
}
|
||||
log.Printf("[INFO] Starting test provider %s", addr)
|
||||
inst, err := factory()
|
||||
if err != nil {
|
||||
log.Printf("[WARN] Unable to start provider %s in test context", addr)
|
||||
providerInstances[addr.Provider] = nil
|
||||
return nil
|
||||
} else {
|
||||
log.Printf("[INFO] Shutting down test provider %s", addr)
|
||||
providerInstances[addr.Provider] = inst
|
||||
return inst
|
||||
}
|
||||
}
|
||||
|
||||
scope := &lang.Scope{
|
||||
Data: data,
|
||||
BaseDir: ".",
|
||||
PureOnly: operation != walkApply,
|
||||
PlanTimestamp: ctx.Plan.Timestamp,
|
||||
ProviderFunctions: func(pf addrs.ProviderFunction, rng tfdiags.SourceRange) (*function.Function, tfdiags.Diagnostics) {
|
||||
return evalContextProviderFunction(providerSupplier, ctx.Config, walkPlan, pf, rng)
|
||||
},
|
||||
}
|
||||
|
||||
// We're going to assume the run has passed, and then if anything fails this
|
||||
|
Loading…
Reference in New Issue
Block a user