Skip to content

Commit 7b6eb10

Browse files
authored
Add Validate for StateStore (#1272)
* changed years to 2026 * update copywrite version * updated merged copywrite years * Added Validate for Statestore * Addressed naming comments * adjust merge conflict * adjust for linter
1 parent 9bd8a09 commit 7b6eb10

17 files changed

+1074
-7
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright IBM Corp. 2021, 2026
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package fromproto6
5+
6+
import (
7+
"context"
8+
9+
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
10+
11+
"github.com/hashicorp/terraform-plugin-framework/diag"
12+
"github.com/hashicorp/terraform-plugin-framework/internal/fwschema"
13+
"github.com/hashicorp/terraform-plugin-framework/internal/fwserver"
14+
"github.com/hashicorp/terraform-plugin-framework/statestore"
15+
)
16+
17+
// ValidateStateStoreConfigRequest returns the *fwserver.ValidateStateStoreConfigRequest
18+
// equivalent of a *tfprotov6.ValidateStateStoreConfigRequest.
19+
func ValidateStateStoreConfigRequest(ctx context.Context, proto6 *tfprotov6.ValidateStateStoreConfigRequest, reqStateStore statestore.StateStore, statestoreSchema fwschema.Schema) (*fwserver.ValidateStateStoreConfigRequest, diag.Diagnostics) {
20+
if proto6 == nil {
21+
return nil, nil
22+
}
23+
24+
fw := &fwserver.ValidateStateStoreConfigRequest{}
25+
26+
config, diags := Config(ctx, proto6.Config, statestoreSchema)
27+
28+
fw.Config = config
29+
fw.StateStore = reqStateStore
30+
31+
return fw, diags
32+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// Copyright IBM Corp. 2021, 2026
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package fromproto6_test
5+
6+
import (
7+
"context"
8+
"testing"
9+
10+
"github.com/google/go-cmp/cmp"
11+
"github.com/hashicorp/terraform-plugin-framework/diag"
12+
"github.com/hashicorp/terraform-plugin-framework/internal/fromproto6"
13+
"github.com/hashicorp/terraform-plugin-framework/internal/fwschema"
14+
"github.com/hashicorp/terraform-plugin-framework/internal/fwserver"
15+
"github.com/hashicorp/terraform-plugin-framework/statestore"
16+
"github.com/hashicorp/terraform-plugin-framework/statestore/schema"
17+
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
18+
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
19+
"github.com/hashicorp/terraform-plugin-go/tftypes"
20+
)
21+
22+
func TestValidateStateStoreConfigRequest(t *testing.T) {
23+
t.Parallel()
24+
25+
testProto6Type := tftypes.Object{
26+
AttributeTypes: map[string]tftypes.Type{
27+
"test_attribute": tftypes.String,
28+
},
29+
}
30+
31+
testProto6Value := tftypes.NewValue(testProto6Type, map[string]tftypes.Value{
32+
"test_attribute": tftypes.NewValue(tftypes.String, "test-value"),
33+
})
34+
35+
testProto6DynamicValue, err := tfprotov6.NewDynamicValue(testProto6Type, testProto6Value)
36+
37+
if err != nil {
38+
t.Fatalf("unexpected error calling tfprotov6.NewDynamicValue(): %s", err)
39+
}
40+
41+
testFwSchema := schema.Schema{
42+
Attributes: map[string]schema.Attribute{
43+
"test_attribute": schema.StringAttribute{
44+
Required: true,
45+
},
46+
},
47+
}
48+
49+
testCases := map[string]struct {
50+
input *tfprotov6.ValidateStateStoreConfigRequest
51+
statestoreSchema fwschema.Schema
52+
statestoreImpl statestore.StateStore
53+
expected *fwserver.ValidateStateStoreConfigRequest
54+
expectedDiagnostics diag.Diagnostics
55+
}{
56+
"nil": {
57+
input: nil,
58+
expected: nil,
59+
},
60+
"empty": {
61+
input: &tfprotov6.ValidateStateStoreConfigRequest{},
62+
expected: &fwserver.ValidateStateStoreConfigRequest{},
63+
},
64+
"config-missing-schema": {
65+
input: &tfprotov6.ValidateStateStoreConfigRequest{
66+
Config: &testProto6DynamicValue,
67+
},
68+
expected: &fwserver.ValidateStateStoreConfigRequest{},
69+
expectedDiagnostics: diag.Diagnostics{
70+
diag.NewErrorDiagnostic(
71+
"Unable to Convert Configuration",
72+
"An unexpected error was encountered when converting the configuration from the protocol type. "+
73+
"This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+
74+
"Please report this to the provider developer:\n\n"+
75+
"Missing schema.",
76+
),
77+
},
78+
},
79+
"config": {
80+
input: &tfprotov6.ValidateStateStoreConfigRequest{
81+
Config: &testProto6DynamicValue,
82+
},
83+
statestoreSchema: testFwSchema,
84+
expected: &fwserver.ValidateStateStoreConfigRequest{
85+
Config: &tfsdk.Config{
86+
Raw: testProto6Value,
87+
Schema: testFwSchema,
88+
},
89+
},
90+
},
91+
}
92+
93+
for name, testCase := range testCases {
94+
t.Run(name, func(t *testing.T) {
95+
t.Parallel()
96+
97+
got, diags := fromproto6.ValidateStateStoreConfigRequest(context.Background(), testCase.input, testCase.statestoreImpl, testCase.statestoreSchema)
98+
99+
if diff := cmp.Diff(got, testCase.expected); diff != "" {
100+
t.Errorf("unexpected difference: %s", diff)
101+
}
102+
103+
if diff := cmp.Diff(diags, testCase.expectedDiagnostics); diff != "" {
104+
t.Errorf("unexpected diagnostics difference: %s", diff)
105+
}
106+
})
107+
}
108+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// Copyright IBM Corp. 2021, 2026
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package fwserver
5+
6+
import (
7+
"context"
8+
9+
"github.com/hashicorp/terraform-plugin-framework/diag"
10+
"github.com/hashicorp/terraform-plugin-framework/internal/logging"
11+
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
12+
"github.com/hashicorp/terraform-plugin-framework/statestore"
13+
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
14+
)
15+
16+
// ValidateStateStoreConfigRequest is the framework server request for the
17+
// ValidateStateStoreConfig RPC.
18+
type ValidateStateStoreConfigRequest struct {
19+
Config *tfsdk.Config
20+
StateStore statestore.StateStore
21+
}
22+
23+
// ValidateStateStoreConfigResponse is the framework server response for the
24+
// ValidateStateStoreConfig RPC.
25+
type ValidateStateStoreConfigResponse struct {
26+
Diagnostics diag.Diagnostics
27+
}
28+
29+
// ValidateStateStoreConfig implements the framework server ValidateStateStoreConfig RPC.
30+
func (s *Server) ValidateStateStoreConfig(ctx context.Context, req *ValidateStateStoreConfigRequest, resp *ValidateStateStoreConfigResponse) {
31+
if req == nil || req.Config == nil {
32+
return
33+
}
34+
35+
if statestoreWithConfigure, ok := req.StateStore.(statestore.StateStoreWithConfigure); ok {
36+
logging.FrameworkTrace(ctx, "StateStore implements StateStoreWithConfigure")
37+
38+
configureReq := statestore.ConfigureRequest{
39+
StateStoreData: s.StateStoreConfigureData.StateStoreConfigureData,
40+
}
41+
configureResp := statestore.ConfigureResponse{}
42+
43+
logging.FrameworkTrace(ctx, "Calling provider defined StateStore Configure")
44+
statestoreWithConfigure.Configure(ctx, configureReq, &configureResp)
45+
logging.FrameworkTrace(ctx, "Called provider defined StateStore Configure")
46+
47+
resp.Diagnostics.Append(configureResp.Diagnostics...)
48+
49+
if resp.Diagnostics.HasError() {
50+
return
51+
}
52+
}
53+
54+
vdscReq := statestore.ValidateConfigRequest{
55+
Config: *req.Config,
56+
}
57+
58+
if statestoreWithConfigValidators, ok := req.StateStore.(statestore.StateStoreWithConfigValidators); ok {
59+
logging.FrameworkTrace(ctx, "StateStore implements StateStoreWithConfigValidators")
60+
61+
for _, configValidator := range statestoreWithConfigValidators.ConfigValidators(ctx) {
62+
// Instantiate a new response for each request to prevent validators
63+
// from modifying or removing diagnostics.
64+
vdscResp := &statestore.ValidateConfigResponse{}
65+
66+
logging.FrameworkTrace(
67+
ctx,
68+
"Calling provider defined StateStoreConfigValidator",
69+
map[string]interface{}{
70+
logging.KeyDescription: configValidator.Description(ctx),
71+
},
72+
)
73+
configValidator.ValidateStateStore(ctx, vdscReq, vdscResp)
74+
logging.FrameworkTrace(
75+
ctx,
76+
"Called provider defined StateStoreConfigValidator",
77+
map[string]interface{}{
78+
logging.KeyDescription: configValidator.Description(ctx),
79+
},
80+
)
81+
82+
resp.Diagnostics.Append(vdscResp.Diagnostics...)
83+
}
84+
}
85+
86+
if statestoreWithValidateConfig, ok := req.StateStore.(statestore.StateStoreWithValidateConfig); ok {
87+
logging.FrameworkTrace(ctx, "StateStore implements StateStoreWithValidateConfig")
88+
89+
// Instantiate a new response for each request to prevent validators
90+
// from modifying or removing diagnostics.
91+
vdscResp := &statestore.ValidateConfigResponse{}
92+
93+
logging.FrameworkTrace(ctx, "Calling provider defined StateStore ValidateConfig")
94+
statestoreWithValidateConfig.ValidateConfig(ctx, vdscReq, vdscResp)
95+
logging.FrameworkTrace(ctx, "Called provider defined StateStore ValidateConfig")
96+
97+
resp.Diagnostics.Append(vdscResp.Diagnostics...)
98+
}
99+
100+
schemaCapabilities := validator.ValidateSchemaClientCapabilities{
101+
// The SchemaValidate function is shared between provider, resource,
102+
// data source, ephemeral resource, and statestore schemas; however, WriteOnlyAttributesAllowed
103+
// capability is only valid for resource schemas, so this is explicitly set to false
104+
// for all other schema types.
105+
WriteOnlyAttributesAllowed: false,
106+
}
107+
108+
validateSchemaReq := ValidateSchemaRequest{
109+
ClientCapabilities: schemaCapabilities,
110+
Config: *req.Config,
111+
}
112+
// Instantiate a new response for each request to prevent validators
113+
// from modifying or removing diagnostics.
114+
validateSchemaResp := ValidateSchemaResponse{}
115+
116+
SchemaValidate(ctx, req.Config.Schema, validateSchemaReq, &validateSchemaResp)
117+
118+
resp.Diagnostics.Append(validateSchemaResp.Diagnostics...)
119+
}

0 commit comments

Comments
 (0)