[BACKPORT] fix mock provider validation (#2140) (#2196)

Signed-off-by: ollevche <ollevche@gmail.com>
This commit is contained in:
Oleksandr Levchenkov 2024-11-20 17:42:16 +02:00 committed by GitHub
parent e4fd6b9f47
commit 2e04317cb6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 130 additions and 36 deletions

View File

@ -6,6 +6,7 @@
BUG FIXES:
* Provider functions will now handle partially unknown arguments per the tfplugin spec ([#2127](https://github.com/opentofu/opentofu/pull/2127))
* `tofu init` will no longer return a spurious "Backend configuration changed" error when re-initializing a working directory with existing initialization of a backend whose configuration schema has required arguments. This was a regression caused by the similar fix in the v1.8.4 release. ([#2135](https://github.com/opentofu/opentofu/pull/2135))
* The `tofu test` command doesn't try to validate mock provider definition by its underlying provider schema now. ([#2140](https://github.com/opentofu/opentofu/pull/2140))
## 1.8.4

View File

@ -17,6 +17,7 @@ import (
"github.com/opentofu/opentofu/internal/addrs"
testing_command "github.com/opentofu/opentofu/internal/command/testing"
"github.com/opentofu/opentofu/internal/command/views"
"github.com/opentofu/opentofu/internal/configs/configschema"
"github.com/opentofu/opentofu/internal/providers"
"github.com/opentofu/opentofu/internal/terminal"
)
@ -1300,3 +1301,66 @@ digits, underscores, and dashes.
})
}
}
// TestTest_MockProviderValidation checks if tofu test runs proper validation for
// mock_provider. Even if provider schema has required fields, tofu test should
// ignore it completely, because the provider is mocked.
func TestTest_MockProviderValidation(t *testing.T) {
td := t.TempDir()
testCopyDir(t, testFixturePath("test/mock_provider_validation"), td)
defer testChdir(t, td)()
provider := testing_command.NewProvider(nil)
providerSource, closePS := newMockProviderSource(t, map[string][]string{
"test": {"1.0.0"},
})
defer closePS()
provider.Provider.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
Provider: providers.Schema{
Block: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"required_field": {
Type: cty.String,
Required: true,
},
},
},
},
ResourceTypes: map[string]providers.Schema{
"test_resource": {
Block: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"value": {
Type: cty.String,
Optional: true,
},
"computed_value": {
Type: cty.String,
Computed: true,
},
},
},
},
},
}
streams, _ := terminal.StreamsForTesting(t)
view := views.NewView(streams)
ui := new(cli.MockUi)
meta := Meta{
testingOverrides: metaOverridesForProvider(provider.Provider),
Ui: ui,
View: view,
Streams: streams,
ProviderSource: providerSource,
}
testCmd := &TestCommand{
Meta: meta,
}
if code := testCmd.Run(nil); code != 0 {
t.Fatalf("expected status code 0 but got %d: %s", code, ui.ErrorWriter)
}
}

View File

@ -0,0 +1,5 @@
provider "test" {}
resource "test_resource" "primary" {
value = "foo"
}

View File

@ -0,0 +1,14 @@
mock_provider "test" {
mock_resource "test_resource" {
defaults = {
computed_value = "bar"
}
}
}
run "test" {
assert {
condition = test_resource.primary.computed_value == "bar"
error_message = "Unexpected computed value"
}
}

View File

@ -103,28 +103,22 @@ func (p *providerForTest) ReadDataSource(r providers.ReadDataSourceRequest) prov
return resp
}
// Calling the internal provider ensures providerForTest has the same behaviour as if
// it wasn't overridden or mocked. The only exception is ImportResourceState, which panics
// if called via providerForTest because importing is not supported in testing framework.
// ValidateProviderConfig is irrelevant when provider is mocked or overridden.
func (p *providerForTest) ValidateProviderConfig(_ providers.ValidateProviderConfigRequest) providers.ValidateProviderConfigResponse {
return providers.ValidateProviderConfigResponse{}
}
// GetProviderSchema is also used to perform additional validation outside of the provider
// implementation. We are excluding parts of the schema related to provider since it is
// irrelevant in the scope of mocking / overriding. When running `tofu test` configuration
// is being transformed for testing framework and original provider configuration is not
// accessible so it is safe to wipe metadata as well. See Config.transformProviderConfigsForTest
// for more details.
func (p *providerForTest) GetProviderSchema() providers.GetProviderSchemaResponse {
return p.internal.GetProviderSchema()
}
func (p *providerForTest) ValidateProviderConfig(r providers.ValidateProviderConfigRequest) providers.ValidateProviderConfigResponse {
return p.internal.ValidateProviderConfig(r)
}
func (p *providerForTest) ValidateResourceConfig(r providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
return p.internal.ValidateResourceConfig(r)
}
func (p *providerForTest) ValidateDataResourceConfig(r providers.ValidateDataResourceConfigRequest) providers.ValidateDataResourceConfigResponse {
return p.internal.ValidateDataResourceConfig(r)
}
func (p *providerForTest) UpgradeResourceState(r providers.UpgradeResourceStateRequest) providers.UpgradeResourceStateResponse {
return p.internal.UpgradeResourceState(r)
providerSchema := p.internal.GetProviderSchema()
providerSchema.Provider = providers.Schema{}
providerSchema.ProviderMeta = providers.Schema{}
return providerSchema
}
// providerForTest doesn't configure its internal provider because it is mocked.
@ -132,22 +126,6 @@ func (p *providerForTest) ConfigureProvider(_ providers.ConfigureProviderRequest
return providers.ConfigureProviderResponse{}
}
func (p *providerForTest) Stop() error {
return p.internal.Stop()
}
func (p *providerForTest) GetFunctions() providers.GetFunctionsResponse {
return p.internal.GetFunctions()
}
func (p *providerForTest) CallFunction(r providers.CallFunctionRequest) providers.CallFunctionResponse {
return p.internal.CallFunction(r)
}
func (p *providerForTest) Close() error {
return p.internal.Close()
}
func (p *providerForTest) ImportResourceState(providers.ImportResourceStateRequest) providers.ImportResourceStateResponse {
panic("Importing is not supported in testing context. providerForTest must not be used to call ImportResourceState")
}
@ -190,6 +168,38 @@ func (p *providerForTest) addMockResources(mockResources []*configs.MockResource
}
}
// Calling the internal provider ensures providerForTest has the same behaviour as if
// it wasn't overridden or mocked. The only exception is ImportResourceState, which panics
// if called via providerForTest because importing is not supported in testing framework.
func (p *providerForTest) ValidateResourceConfig(r providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
return p.internal.ValidateResourceConfig(r)
}
func (p *providerForTest) ValidateDataResourceConfig(r providers.ValidateDataResourceConfigRequest) providers.ValidateDataResourceConfigResponse {
return p.internal.ValidateDataResourceConfig(r)
}
func (p *providerForTest) UpgradeResourceState(r providers.UpgradeResourceStateRequest) providers.UpgradeResourceStateResponse {
return p.internal.UpgradeResourceState(r)
}
func (p *providerForTest) Stop() error {
return p.internal.Stop()
}
func (p *providerForTest) GetFunctions() providers.GetFunctionsResponse {
return p.internal.GetFunctions()
}
func (p *providerForTest) CallFunction(r providers.CallFunctionRequest) providers.CallFunctionResponse {
return p.internal.CallFunction(r)
}
func (p *providerForTest) Close() error {
return p.internal.Close()
}
type resourceForTest struct {
overrideValues map[string]cty.Value
}