fix mock provider validation (#2140)

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

View File

@ -56,6 +56,7 @@ BUG FIXES:
* Error message about a provider type mismatch now correctly identifies which module contains the problem. ([#1991](https://github.com/opentofu/opentofu/pull/1991))
* The `yamldecode` function's interpretation of scalars as numbers now conforms to the YAML 1.2 specification. In particular, the scalar value `+` is now interpreted as the string `"+"` rather than returning a parse error trying to interpret it as an integer. ([#2044](https://github.com/opentofu/opentofu/pull/2044))
* A `module` block's `version` argument now accepts prerelease version selections using a "v" prefix before the version number. Previously this was accepted only for non-prerelease selections. ([#2124])(https://github.com/opentofu/opentofu/issues/2124)
* 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))
INTERNAL CHANGES:

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"
)
@ -1396,3 +1397,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
}