Repository: opentofu/opentofu
File: internal/tofu/provider_for_test_framework.go (Go)

Code before:
// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package tofu

import (
	"context"
	"fmt"
	"hash/fnv"

	"github.com/opentofu/opentofu/internal/addrs"
	"github.com/opentofu/opentofu/internal/configs/hcl2shim"
	"github.com/opentofu/opentofu/internal/providers"
	"github.com/opentofu/opentofu/internal/tfdiags"
	"github.com/zclconf/go-cty/cty"
)

var _ providers.Interface = &providerForTest{}

// providerForTest is a wrapper around a real provider to allow a specific resources to be overridden
// for testing framework.
type providerForTest struct {
	// providers.Interface is not embedded to make it safer to extend
	// the interface without silently breaking providerForTest functionality.
	internal providers.Interface
	schema   providers.ProviderSchema

	overrideValues map[string]cty.Value
}

func newProviderForTestWithSchema(internal providers.Interface, schema providers.ProviderSchema, overrideValues map[string]cty.Value) (providerForTest, error) {
	if schema.Diagnostics.HasErrors() {
		return providerForTest{}, fmt.Errorf("invalid provider schema for test wrapper: %w", schema.Diagnostics.Err())
	}

	return providerForTest{
		internal:       internal,
		schema:         schema,
		overrideValues: overrideValues,
	}, nil
}

func (p providerForTest) ReadResource(_ context.Context, r providers.ReadResourceRequest) providers.ReadResourceResponse {
	var resp providers.ReadResourceResponse

	resp.NewState = r.PriorState

Review comment (bug):
It took me some time to understand what the new meaning of this type is from reading the rest of the changes here, and a future reader of this won't necessarily have the benefit of this diff to refer to, so here's an attempt to put more context here for a future maintainer (and also, as a side-effect, to test whether I understood correctly):


```suggestion
// providerForTest is a special implementation of [providers.Interface] which implements
// only a specific managed or data resource type, implementing it using a fixed override
// value instead of real provider behavior.
//
// This is used by [NodeResourceAbstractInstance.getProvider] when it finds that its
// associated resource instance has had an "override" applied to it using features of the
// module testing language. It creates an object of this type that must only be used
// for operations relating to _that specific resource instance_: using that object for
// any other resource instance will cause unspecified and confusing results.
```

I also wonder if we should reinforce the idea that an object of this type is only for one specific resource instance by including an `addrs.AbsResourceInstance` field inside it. That field would admittedly be mostly unused, but it would at least help a skimming reader quickly notice that (unlike most provider instance types) this particular one has a resource instance address and therefore something weird must be going on.

Once it's there though, we could _actually_ use it in a couple different ways to help detect if we accidentally use this improperly: In `ReadDataSource`, `UpgradeResourceState`, `ReadResource`, `PlanResourceChange`, and `ApplyResourceChange` we could fail immediately if the `Mode` of the resource doesn't make sense for whatever operation was requested, and we could also check if the `req.TypeName` field matches the `Type` of the resource. This wouldn't catch a problem of using the result with a different instance of the same resource type, but it's still a little more robust against mistakes than not checking anything at all. 🤔 


Code after:
// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package tofu

import (
	"context"
	"fmt"
	"hash/fnv"

	"github.com/opentofu/opentofu/internal/addrs"
	"github.com/opentofu/opentofu/internal/configs/hcl2shim"
	"github.com/opentofu/opentofu/internal/providers"
	"github.com/opentofu/opentofu/internal/tfdiags"
	"github.com/zclconf/go-cty/cty"
)

var _ providers.Interface = &providerForTest{}

// providerForTest is a wrapper around a real provider to allow a specific resource to be overridden
// for the testing framework.  It is used by [NodeResourceAbstractInstance.getProvider] to fulfil the mocks
// and overrides for that one specific resource instance, any other usage is a bug in OpenTofu and should
// be corrected.
type providerForTest struct {
	// providers.Interface is not embedded to make it safer to extend
	// the interface without silently breaking providerForTest functionality.
	internal providers.Interface
	schema   providers.ProviderSchema

	overrideValues map[string]cty.Value
}

func newProviderForTestWithSchema(internal providers.Interface, schema providers.ProviderSchema, overrideValues map[string]cty.Value) (providerForTest, error) {
	if schema.Diagnostics.HasErrors() {
		return providerForTest{}, fmt.Errorf("invalid provider schema for test wrapper: %w", schema.Diagnostics.Err())
	}

	return providerForTest{
		internal:       internal,
		schema:         schema,
		overrideValues: overrideValues,
	}, nil
}

func (p providerForTest) ReadResource(_ context.Context, r providers.ReadResourceRequest) providers.ReadResourceResponse {
	var resp providers.ReadResourceResponse