Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ParseConfig should call the custom Validate method #229

Merged
merged 5 commits into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions acceptance_testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -1153,11 +1153,6 @@ func configureSource(ctx context.Context, src Source, cfgMap config.Config, para
return fmt.Errorf("failed to parse configuration: %w", err)
}

err = cfg.Validate(ctx)
if err != nil {
return fmt.Errorf("configuration invalid: %w", err)
}

return nil
}

Expand All @@ -1173,10 +1168,5 @@ func configureDestination(ctx context.Context, dest Destination, cfgMap config.C
return fmt.Errorf("failed to parse configuration: %w", err)
}

err = cfg.Validate(ctx)
if err != nil {
return fmt.Errorf("configuration invalid: %w", err)
}

return nil
}
5 changes: 0 additions & 5 deletions destination.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,6 @@ func (a *destinationPluginAdapter) Configure(ctx context.Context, req pconnector
return pconnector.DestinationConfigureResponse{}, fmt.Errorf("failed to parse configuration: %w", err)
}

err = cfg.Validate(ctx)
if err != nil {
return pconnector.DestinationConfigureResponse{}, fmt.Errorf("configuration invalid: %w", err)
}

return pconnector.DestinationConfigureResponse{}, nil
}

Expand Down
12 changes: 4 additions & 8 deletions source.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,10 @@ type Source interface {
// update anything that was initialized in LifecycleOnCreated, in case the
// configuration change affects it.
LifecycleOnUpdated(ctx context.Context, configBefore, configAfter config.Config) error
// LifecycleOnDeleted is called when the connector was deleted. It will be
// the only method that is called in that case. This method can be used to
// clean up anything that was initialized in LifecycleOnCreated.
// LifecycleOnDeleted is called when the connector was deleted.
// This method can be used to clean up anything that was initialized in LifecycleOnCreated.
// It will be the only method that is called in that case, i.e. Configure() and Open()
// won't be called. The implementation needs to manually parse the configuration if needed.
LifecycleOnDeleted(ctx context.Context, config config.Config) error

mustEmbedUnimplementedSource()
Expand Down Expand Up @@ -181,11 +182,6 @@ func (a *sourcePluginAdapter) Configure(ctx context.Context, req pconnector.Sour
return fmt.Errorf("failed to parse configuration: %w", err)
}

err = cfg.Validate(ctx)
if err != nil {
return fmt.Errorf("configuration invalid: %w", err)
}

return nil
})

Expand Down
14 changes: 12 additions & 2 deletions util.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,18 @@ func parseConfig(
}

logger.Debug().Type("target", target).Msg("decoding configuration into the target object")
//nolint:wrapcheck // error is already wrapped by DecodeInto
return c.DecodeInto(target)
if err := c.DecodeInto(target); err != nil {
return err
}

if v, ok := target.(Validatable); ok {
err := v.Validate(ctx)
if err != nil {
return fmt.Errorf("config invalid: %w", err)
}
}

return err
}

func YAMLSpecification(rawYaml string) func() Specification {
Expand Down
58 changes: 58 additions & 0 deletions util_example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright © 2022 Meroxa, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package sdk

import (
"context"
"fmt"
"time"

"github.com/conduitio/conduit-commons/config"
)

// ExampleUtil_ParseConfig shows the usage of Util.ParseConfig.
func ExampleUtil_ParseConfig() {
cfg := config.Config{
"foo": "bar ", // will be sanitized
// "bar" is missing, will be set to the default value
"nested.baz": "1m",
}

params := config.Parameters{
"foo": config.Parameter{Type: config.ParameterTypeString},
"bar": config.Parameter{
Type: config.ParameterTypeInt,
Default: "42",
},
"nested.baz": config.Parameter{Type: config.ParameterTypeDuration},
}

var target struct {
Foo string `json:"foo"`
Bar int `json:"bar"`
Nested struct {
Baz time.Duration `json:"baz"`
} `json:"nested"`
}

err := Util.ParseConfig(context.Background(), cfg, &target, params)
if err != nil {
panic(err)
}

fmt.Printf("%+v", target)

// Output: {Foo:bar Bar:42 Nested:{Baz:1m0s}}
}
49 changes: 24 additions & 25 deletions util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,43 +16,42 @@ package sdk

import (
"context"
"fmt"
"errors"
"testing"
"time"

"github.com/conduitio/conduit-commons/config"
"github.com/matryer/is"
)

// ExampleUtil_ParseConfig shows the usage of Util.ParseConfig.
func ExampleUtil_ParseConfig() {
type testConfig struct {
Foo string `json:"foo"`
Bar int `json:"bar"`
Nested struct {
Baz time.Duration `json:"baz"`
} `json:"nested"`
err error
}

func (c *testConfig) Validate(context.Context) error {
return c.err
}

func TestParseConfig_ValidateCalled(t *testing.T) {
is := is.New(t)

wantErr := errors.New("validation error")
cfg := config.Config{
"foo": "bar ", // will be sanitized
// "bar" is missing, will be set to the default value
"nested.baz": "1m",
"foo": "bar",
}

params := config.Parameters{
"foo": config.Parameter{Type: config.ParameterTypeString},
"bar": config.Parameter{
Type: config.ParameterTypeInt,
Default: "42",
},
"nested.baz": config.Parameter{Type: config.ParameterTypeDuration},
}

var target struct {
Foo string `json:"foo"`
Bar int `json:"bar"`
Nested struct {
Baz time.Duration `json:"baz"`
} `json:"nested"`
target := testConfig{
err: wantErr,
}

err := Util.ParseConfig(context.Background(), cfg, &target, params)
if err != nil {
panic(err)
}

fmt.Printf("%+v", target)

// Output: {Foo:bar Bar:42 Nested:{Baz:1m0s}}
is.True(errors.Is(err, wantErr))
}
Loading