From 00356b5d3061c2278877b9f49dc93654feffdb21 Mon Sep 17 00:00:00 2001 From: almostinf Date: Fri, 4 Oct 2024 20:20:25 +0300 Subject: [PATCH] add generic ValidateConfig function --- helpers.go | 8 ++++++ helpers_test.go | 56 ++++++++++++++++++++++++++++++++---- senders/discord/init.go | 8 +----- senders/mail/mail.go | 8 +----- senders/mattermost/sender.go | 8 +----- senders/msteams/msteams.go | 8 +----- senders/opsgenie/init.go | 8 +----- senders/pushover/pushover.go | 8 +----- senders/script/script.go | 8 +----- senders/slack/slack.go | 8 +----- senders/telegram/init.go | 8 +----- senders/twilio/twilio.go | 8 +----- senders/victorops/init.go | 8 +----- senders/webhook/webhook.go | 8 +----- 14 files changed, 71 insertions(+), 89 deletions(-) diff --git a/helpers.go b/helpers.go index c0432ca21..54e991347 100644 --- a/helpers.go +++ b/helpers.go @@ -5,6 +5,8 @@ import ( "math" "strings" "time" + + "github.com/go-playground/validator/v10" ) // BytesScanner allows to scan for subslices separated by separator. @@ -250,3 +252,9 @@ func MergeToSorted[T Comparable](arr1, arr2 []T) ([]T, error) { return merged, nil } + +// ValidateConfig is a generic function needed to validate the config structure using validator. +func ValidateConfig(cfg any) error { + validator := validator.New() + return validator.Struct(cfg) +} diff --git a/helpers_test.go b/helpers_test.go index d9c3ca4ee..c83516e97 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -290,25 +290,25 @@ func TestMergeToSorted(t *testing.T) { }) Convey("Test with one nil array", func() { - merged, err := MergeToSorted[myInt](nil, []myInt{1, 2, 3}) + merged, err := MergeToSorted(nil, []myInt{1, 2, 3}) So(err, ShouldBeNil) So(merged, ShouldResemble, []myInt{1, 2, 3}) }) Convey("Test with two arrays", func() { - merged, err := MergeToSorted[myInt]([]myInt{4, 5}, []myInt{1, 2, 3}) + merged, err := MergeToSorted([]myInt{4, 5}, []myInt{1, 2, 3}) So(err, ShouldBeNil) So(merged, ShouldResemble, []myInt{1, 2, 3, 4, 5}) }) Convey("Test with empty array", func() { - merged, err := MergeToSorted[myInt]([]myInt{-4, 5}, []myInt{}) + merged, err := MergeToSorted([]myInt{-4, 5}, []myInt{}) So(err, ShouldBeNil) So(merged, ShouldResemble, []myInt{-4, 5}) }) Convey("Test with sorted values but mixed up", func() { - merged, err := MergeToSorted[myInt]([]myInt{1, 9, 10}, []myInt{4, 8, 12}) + merged, err := MergeToSorted([]myInt{1, 9, 10}, []myInt{4, 8, 12}) So(err, ShouldBeNil) So(merged, ShouldResemble, []myInt{1, 4, 8, 9, 10, 12}) }) @@ -333,9 +333,55 @@ func TestMergeToSorted(t *testing.T) { } expected := append(arr2, arr1...) - merged, err := MergeToSorted[myTest](arr1, arr2) + merged, err := MergeToSorted(arr1, arr2) So(err, ShouldBeNil) So(merged, ShouldResemble, expected) }) }) } + +func TestValidateConfig(t *testing.T) { + type ValidationStruct struct { + TestInt int `validate:"required,gt=0"` + TestURL string `validate:"required,url"` + TestBool bool + } + + const ( + validURL = "https://github.com/moira-alert/moira" + validInt = 1 + ) + + Convey("Test ValidateConfig", t, func() { + Convey("With TestInt less than zero", func() { + testStruct := ValidationStruct{ + TestInt: -1, + TestURL: validURL, + } + + err := ValidateConfig(testStruct) + So(err, ShouldNotBeNil) + }) + + Convey("With invalid TestURL format", func() { + testStruct := ValidationStruct{ + TestInt: validInt, + TestURL: "test", + TestBool: true, + } + + err := ValidateConfig(testStruct) + So(err, ShouldNotBeNil) + }) + + Convey("With valid structure", func() { + testStruct := ValidationStruct{ + TestInt: validInt, + TestURL: validURL, + } + + err := ValidateConfig(testStruct) + So(err, ShouldBeNil) + }) + }) +} diff --git a/senders/discord/init.go b/senders/discord/init.go index 946733426..04d6a2bc3 100644 --- a/senders/discord/init.go +++ b/senders/discord/init.go @@ -5,7 +5,6 @@ import ( "time" "github.com/bwmarrin/discordgo" - "github.com/go-playground/validator/v10" "github.com/mitchellh/mapstructure" "github.com/moira-alert/moira" "github.com/moira-alert/moira/worker" @@ -25,11 +24,6 @@ type config struct { FrontURI string `mapstructure:"front_uri"` } -func (cfg config) validate() error { - validator := validator.New() - return validator.Struct(cfg) -} - // Sender implements moira sender interface for discord. type Sender struct { DataBase moira.Database @@ -48,7 +42,7 @@ func (sender *Sender) Init(senderSettings interface{}, logger moira.Logger, loca return fmt.Errorf("failed to decode senderSettings to discord config: %w", err) } - if err = cfg.validate(); err != nil { + if err = moira.ValidateConfig(cfg); err != nil { return fmt.Errorf("discord config validation error: %w", err) } diff --git a/senders/mail/mail.go b/senders/mail/mail.go index 71d638425..95588f090 100644 --- a/senders/mail/mail.go +++ b/senders/mail/mail.go @@ -8,7 +8,6 @@ import ( "path/filepath" "time" - "github.com/go-playground/validator/v10" "github.com/mitchellh/mapstructure" "github.com/moira-alert/moira" ) @@ -26,11 +25,6 @@ type config struct { TemplateFile string `mapstructure:"template_file"` } -func (cfg config) validate() error { - validator := validator.New() - return validator.Struct(cfg) -} - // Sender implements moira sender interface via pushover. type Sender struct { From string @@ -70,7 +64,7 @@ func (sender *Sender) fillSettings(senderSettings interface{}, logger moira.Logg return fmt.Errorf("failed to decode senderSettings to mail config: %w", err) } - if err = cfg.validate(); err != nil { + if err = moira.ValidateConfig(cfg); err != nil { return fmt.Errorf("mail config validation error: %w", err) } diff --git a/senders/mattermost/sender.go b/senders/mattermost/sender.go index 0207404ee..076d4dc80 100644 --- a/senders/mattermost/sender.go +++ b/senders/mattermost/sender.go @@ -7,7 +7,6 @@ import ( "net/http" "time" - "github.com/go-playground/validator/v10" "github.com/moira-alert/moira/senders/msgformat" "github.com/moira-alert/moira" @@ -28,11 +27,6 @@ type config struct { EmojiMap map[string]string `mapstructure:"emoji_map"` } -func (cfg config) validate() error { - validator := validator.New() - return validator.Struct(cfg) -} - // Sender posts messages to Mattermost chat. // It implements moira.Sender. // You must call Init method before SendEvents method. @@ -59,7 +53,7 @@ func (sender *Sender) Init(senderSettings interface{}, logger moira.Logger, loca return fmt.Errorf("failed to decode senderSettings to mattermost config: %w", err) } - if err = cfg.validate(); err != nil { + if err = moira.ValidateConfig(cfg); err != nil { return fmt.Errorf("mattermost config validation error: %w", err) } diff --git a/senders/msteams/msteams.go b/senders/msteams/msteams.go index f497f1a4a..232b4f335 100644 --- a/senders/msteams/msteams.go +++ b/senders/msteams/msteams.go @@ -11,7 +11,6 @@ import ( "strings" "time" - "github.com/go-playground/validator/v10" "github.com/mitchellh/mapstructure" "github.com/moira-alert/moira" "github.com/russross/blackfriday/v2" @@ -50,11 +49,6 @@ type config struct { MaxEvents int `mapstructure:"max_events"` } -func (cfg config) validate() error { - validator := validator.New() - return validator.Struct(cfg) -} - // Sender implements moira sender interface via MS Teams. type Sender struct { frontURI string @@ -72,7 +66,7 @@ func (sender *Sender) Init(senderSettings interface{}, logger moira.Logger, loca return fmt.Errorf("failed to decode senderSettings to msteams config: %w", err) } - if err = cfg.validate(); err != nil { + if err = moira.ValidateConfig(cfg); err != nil { return fmt.Errorf("msteams config validation error: %w", err) } diff --git a/senders/opsgenie/init.go b/senders/opsgenie/init.go index c411fa789..826e2dffe 100644 --- a/senders/opsgenie/init.go +++ b/senders/opsgenie/init.go @@ -4,7 +4,6 @@ import ( "fmt" "time" - "github.com/go-playground/validator/v10" "github.com/mitchellh/mapstructure" "github.com/moira-alert/moira" "github.com/moira-alert/moira/senders" @@ -17,11 +16,6 @@ type config struct { APIKey string `mapstructure:"api_key" validate:"required"` } -func (cfg config) validate() error { - validator := validator.New() - return validator.Struct(cfg) -} - // Sender implements the Sender interface for opsgenie. type Sender struct { apiKey string @@ -43,7 +37,7 @@ func (sender *Sender) Init(senderSettings interface{}, logger moira.Logger, loca return fmt.Errorf("failed to decode senderSettings to opsgenie config: %w", err) } - if err = cfg.validate(); err != nil { + if err = moira.ValidateConfig(cfg); err != nil { return fmt.Errorf("opsgenie config validation error: %w", err) } diff --git a/senders/pushover/pushover.go b/senders/pushover/pushover.go index 2497bcd9a..ebef420be 100644 --- a/senders/pushover/pushover.go +++ b/senders/pushover/pushover.go @@ -5,7 +5,6 @@ import ( "fmt" "time" - "github.com/go-playground/validator/v10" "github.com/moira-alert/moira" pushover_client "github.com/gregdel/pushover" @@ -24,11 +23,6 @@ type config struct { FrontURI string `mapstructure:"front_uri"` } -func (cfg config) validate() error { - validator := validator.New() - return validator.Struct(cfg) -} - // Sender implements moira sender interface via pushover. type Sender struct { logger moira.Logger @@ -47,7 +41,7 @@ func (sender *Sender) Init(senderSettings interface{}, logger moira.Logger, loca return fmt.Errorf("failed to decode senderSettings to pushover config: %w", err) } - if err = cfg.validate(); err != nil { + if err = moira.ValidateConfig(cfg); err != nil { return fmt.Errorf("pushover config validation error: %w", err) } diff --git a/senders/script/script.go b/senders/script/script.go index e3eb0cfc7..b3f4487e4 100644 --- a/senders/script/script.go +++ b/senders/script/script.go @@ -9,7 +9,6 @@ import ( "strings" "time" - "github.com/go-playground/validator/v10" "github.com/mitchellh/mapstructure" "github.com/moira-alert/moira" ) @@ -19,11 +18,6 @@ type config struct { Exec string `mapstructure:"exec" validate:"required"` } -func (cfg config) validate() error { - validator := validator.New() - return validator.Struct(cfg) -} - // Sender implements moira sender interface via script execution. type Sender struct { exec string @@ -46,7 +40,7 @@ func (sender *Sender) Init(senderSettings interface{}, logger moira.Logger, loca return fmt.Errorf("failed to decode senderSettings to script config: %w", err) } - if err = cfg.validate(); err != nil { + if err = moira.ValidateConfig(cfg); err != nil { return fmt.Errorf("script config validation error: %w", err) } diff --git a/senders/slack/slack.go b/senders/slack/slack.go index 8a4958e22..74331da97 100644 --- a/senders/slack/slack.go +++ b/senders/slack/slack.go @@ -5,7 +5,6 @@ import ( "fmt" "time" - "github.com/go-playground/validator/v10" "github.com/moira-alert/moira/senders/msgformat" "github.com/mitchellh/mapstructure" @@ -39,11 +38,6 @@ type config struct { EmojiMap map[string]string `mapstructure:"emoji_map"` } -func (cfg config) validate() error { - validator := validator.New() - return validator.Struct(cfg) -} - // Sender implements moira sender interface via slack. type Sender struct { emojiProvider emoji_provider.StateEmojiGetter @@ -60,7 +54,7 @@ func (sender *Sender) Init(senderSettings interface{}, logger moira.Logger, loca return fmt.Errorf("failed to decode senderSettings to slack config: %w", err) } - if err = cfg.validate(); err != nil { + if err = moira.ValidateConfig(cfg); err != nil { return fmt.Errorf("slack config validation error: %w", err) } diff --git a/senders/telegram/init.go b/senders/telegram/init.go index c3a443416..49ffafe26 100644 --- a/senders/telegram/init.go +++ b/senders/telegram/init.go @@ -6,7 +6,6 @@ import ( "strings" "time" - "github.com/go-playground/validator/v10" "github.com/moira-alert/moira/senders/msgformat" "github.com/mitchellh/mapstructure" @@ -32,11 +31,6 @@ type config struct { FrontURI string `mapstructure:"front_uri"` } -func (cfg config) validate() error { - validator := validator.New() - return validator.Struct(cfg) -} - // Bot is abstraction over gopkg.in/telebot.v3#Bot. type Bot interface { Handle(endpoint interface{}, h telebot.HandlerFunc, m ...telebot.MiddlewareFunc) @@ -72,7 +66,7 @@ func (sender *Sender) Init(senderSettings interface{}, logger moira.Logger, loca return fmt.Errorf("failed to decode senderSettings to telegram config: %w", err) } - if err = cfg.validate(); err != nil { + if err = moira.ValidateConfig(cfg); err != nil { return fmt.Errorf("telegram config validation error: %w", err) } diff --git a/senders/twilio/twilio.go b/senders/twilio/twilio.go index c4f4e1ffd..4910bccb7 100644 --- a/senders/twilio/twilio.go +++ b/senders/twilio/twilio.go @@ -5,7 +5,6 @@ import ( "time" twilio_client "github.com/carlosdp/twiliogo" - "github.com/go-playground/validator/v10" "github.com/mitchellh/mapstructure" "github.com/moira-alert/moira" ) @@ -21,11 +20,6 @@ type config struct { AppendMessage bool `mapstructure:"append_message"` } -func (cfg config) validate() error { - validator := validator.New() - return validator.Struct(cfg) -} - // Sender implements moira sender interface via twilio. type Sender struct { sender sendEventsTwilio @@ -50,7 +44,7 @@ func (sender *Sender) Init(senderSettings interface{}, logger moira.Logger, loca return fmt.Errorf("failed to decode senderSettings to twilio config: %w", err) } - if err = cfg.validate(); err != nil { + if err = moira.ValidateConfig(cfg); err != nil { return fmt.Errorf("twilio config validation error: %w", err) } diff --git a/senders/victorops/init.go b/senders/victorops/init.go index 5e6719482..a9de7e96f 100644 --- a/senders/victorops/init.go +++ b/senders/victorops/init.go @@ -4,7 +4,6 @@ import ( "fmt" "time" - "github.com/go-playground/validator/v10" "github.com/mitchellh/mapstructure" "github.com/moira-alert/moira/senders/victorops/api" @@ -18,11 +17,6 @@ type config struct { FrontURI string `mapstructure:"front_uri"` } -func (cfg config) validate() error { - validator := validator.New() - return validator.Struct(cfg) -} - // Sender implements moira sender interface for victorops. type Sender struct { DataBase moira.Database @@ -46,7 +40,7 @@ func (sender *Sender) Init(senderSettings interface{}, logger moira.Logger, loca return fmt.Errorf("failed to decode senderSettings to victorops config: %w", err) } - if err = cfg.validate(); err != nil { + if err = moira.ValidateConfig(cfg); err != nil { return fmt.Errorf("victorops config validation error: %w", err) } diff --git a/senders/webhook/webhook.go b/senders/webhook/webhook.go index 9c1f743c4..6c649e1de 100644 --- a/senders/webhook/webhook.go +++ b/senders/webhook/webhook.go @@ -6,7 +6,6 @@ import ( "net/http" "time" - "github.com/go-playground/validator/v10" "github.com/mitchellh/mapstructure" "github.com/moira-alert/moira" ) @@ -21,11 +20,6 @@ type config struct { Timeout int `mapstructure:"timeout"` } -func (cfg config) validate() error { - validator := validator.New() - return validator.Struct(cfg) -} - // Sender implements moira sender interface via webhook. type Sender struct { url string @@ -45,7 +39,7 @@ func (sender *Sender) Init(senderSettings interface{}, logger moira.Logger, loca return fmt.Errorf("failed to decode senderSettings to webhook config: %w", err) } - if err = cfg.validate(); err != nil { + if err = moira.ValidateConfig(cfg); err != nil { return fmt.Errorf("webhook config validation error: %w", err) }