From 0b7dbc3365bd6e6551069950f036ba9803810f21 Mon Sep 17 00:00:00 2001 From: Mateusz Hawrus Date: Mon, 1 Jul 2024 21:18:00 +0200 Subject: [PATCH] rewrite examples --- internal/cmd/examplegen/main.go | 163 +++++++++--------- .../manifest/v1alpha/examples/alert_method.go | 85 +++++---- .../v1alpha/examples/alert_method_test.go | 19 ++ .../manifest/v1alpha/examples/alert_policy.go | 1 + internal/manifest/v1alpha/examples/example.go | 41 +++++ internal/manifest/v1alpha/examples/labels.go | 8 +- .../v1alpha/examples/metadata_annotations.go | 8 +- internal/manifest/v1alpha/examples/project.go | 26 +-- internal/manifest/v1alpha/examples/service.go | 24 +-- internal/manifest/v1alpha/examples/slo.go | 18 +- .../manifest/v1alpha/examples/slo_test.go | 4 +- .../manifest/v1alpha/examples/slo_variants.go | 40 ++++- .../v1alpha/examples/validation_test.go | 39 +++-- manifest/v1alpha/data_sources.go | 6 +- manifest/v1alpha/labels.go | 4 +- manifest/v1alpha/metadata_annotations.go | 4 +- 16 files changed, 313 insertions(+), 177 deletions(-) create mode 100644 internal/manifest/v1alpha/examples/alert_method_test.go create mode 100644 internal/manifest/v1alpha/examples/alert_policy.go create mode 100644 internal/manifest/v1alpha/examples/example.go diff --git a/internal/cmd/examplegen/main.go b/internal/cmd/examplegen/main.go index 8c8a0813..5e876589 100644 --- a/internal/cmd/examplegen/main.go +++ b/internal/cmd/examplegen/main.go @@ -4,7 +4,6 @@ import ( "fmt" "os" "path/filepath" - "slices" "strings" "github.com/goccy/go-yaml" @@ -12,15 +11,13 @@ import ( v1alphaExamples "github.com/nobl9/nobl9-go/internal/manifest/v1alpha/examples" "github.com/nobl9/nobl9-go/internal/pathutils" "github.com/nobl9/nobl9-go/manifest" - "github.com/nobl9/nobl9-go/manifest/v1alpha" - v1alphaSLO "github.com/nobl9/nobl9-go/manifest/v1alpha/slo" "github.com/nobl9/nobl9-go/sdk" ) type examplesGeneratorFunc func() any type examplesGeneratorConfig struct { - Generate examplesGeneratorFunc + Examples []v1alphaExamples.Example Path string Comments yaml.CommentMap } @@ -31,20 +28,82 @@ func main() { rootPath := pathutils.FindModuleRoot() configs := getV1alphaExamplesConfigs() for _, config := range configs { - v := config.Generate() - if object, ok := v.(manifest.Object); ok && config.Path == "" { - config.Path = filepath.Join( - manifestPath, - object.GetVersion().VersionString(), - object.GetKind().ToLower(), - "examples.yaml", - ) + for _, variant := range config.Examples { + v := variant.GetObject() + if object, ok := v.(manifest.Object); ok && config.Path == "" { + config.Path = filepath.Join( + manifestPath, + object.GetVersion().VersionString(), + object.GetKind().ToLower(), + "examples.yaml", + ) + } + config.Path = filepath.Join(rootPath, config.Path) + if err := writeExamples(v, config.Path, config.Comments); err != nil { + errFatal(err.Error()) + } + } + } +} + +func getV1alphaExamplesConfigs() []examplesGeneratorConfig { + basePath := filepath.Join(manifestPath, "v1alpha") + // Non-standard examples. + configs := []examplesGeneratorConfig{ + { + Examples: v1alphaExamples.Labels(), + Path: filepath.Join(basePath, "labels_examples.yaml"), + }, + { + Examples: v1alphaExamples.MetadataAnnotations(), + Path: filepath.Join(basePath, "metadata_annotations_examples.yaml"), + }, + } + // Standard examples. + allExamples := [][]v1alphaExamples.Example{ + v1alphaExamples.Project(), + v1alphaExamples.Service(), + v1alphaExamples.AlertMethod(), + v1alphaExamples.SLO(), + } + for _, examples := range allExamples { + object := examples[0].(manifest.Object) + basePath := filepath.Join( + manifestPath, + object.GetVersion().VersionString(), + object.GetKind().ToLower(), + ) + grouped := groupBy(examples, func(e v1alphaExamples.Example) string { return e.GetVariant() }) + // If we don't have any variants, we can write all examples into examples.yaml file. + if len(grouped) == 1 { + configs = append(configs, examplesGeneratorConfig{ + Examples: examples, + Path: filepath.Join(basePath, "examples.yaml"), + }) + continue } - config.Path = filepath.Join(rootPath, config.Path) - if err := writeExamples(v, config.Path, config.Comments); err != nil { - errFatal(err.Error()) + for variant, examples := range grouped { + config := examplesGeneratorConfig{ + Examples: examples, + Path: filepath.Join(basePath, "examples", strings.ToLower(variant)+".yaml"), + Comments: make(yaml.CommentMap), + } + if len(examples) == 1 { + configs = append(configs, config) + continue + } + for i, example := range examples { + comments := example.GetYAMLComments() + if len(comments) == 0 { + continue + } + config.Comments[fmt.Sprintf("$[%d]", i)] = []*yaml.Comment{yaml.HeadComment(comments...)} + } + configs = append(configs, config) } } + // config = append(config, getV1alphaSLOExamplesConfigs(path)...) + return configs } func writeExamples(v any, path string, comments yaml.CommentMap) error { @@ -67,78 +126,16 @@ func writeExamples(v any, path string, comments yaml.CommentMap) error { return enc.Encode(v) } -func getV1alphaExamplesConfigs() []examplesGeneratorConfig { - path := filepath.Join(manifestPath, "v1alpha") - config := []examplesGeneratorConfig{ - {Generate: generify(v1alphaExamples.Project)}, - {Generate: generify(v1alphaExamples.Service)}, - { - Generate: generify(v1alphaExamples.Labels), - Path: filepath.Join(path, "labels_examples.yaml"), - }, - { - Generate: generify(v1alphaExamples.MetadataAnnotations), - Path: filepath.Join(path, "metadata_annotations_examples.yaml"), - }, - } - config = append(config, getV1alphaSLOExamplesConfigs(path)...) - return config -} - -func getV1alphaSLOExamplesConfigs(path string) []examplesGeneratorConfig { - variantsPerDataSource := make( - map[v1alpha.DataSourceType][]v1alphaExamples.SLOVariant, - len(v1alpha.DataSourceTypeValues()), - ) - for _, variant := range v1alphaExamples.SLO() { - variantsPerDataSource[variant.DataSourceType] = append( - variantsPerDataSource[variant.DataSourceType], - variant, - ) - } - config := make([]examplesGeneratorConfig, 0, len(variantsPerDataSource)) - for dataSourceType, variants := range variantsPerDataSource { - comments := make(yaml.CommentMap, len(variants)) - for i, variant := range variants { - texts := []string{ - fmt.Sprintf(" Metric type: %s", variant.MetricVariant), - fmt.Sprintf(" Budgeting method: %s", variant.BudgetingMethod), - fmt.Sprintf(" Time window type: %s", variant.TimeWindowType), - } - if variant.MetricSubVariant != "" { - texts = slices.Insert(texts, 1, fmt.Sprintf(" Metric variant: %s", variant.MetricSubVariant)) - } - comments[fmt.Sprintf("$[%d]", i)] = []*yaml.Comment{yaml.HeadComment(texts...)} - } - config = append(config, examplesGeneratorConfig{ - Generate: func() any { - return mapSlice(variants, func(v v1alphaExamples.SLOVariant) v1alphaSLO.SLO { return v.SLO }) - }, - Path: filepath.Join( - path, - "slo", - "examples", - fmt.Sprintf("%s.yaml", strings.ToLower(dataSourceType.String())), - ), - Comments: comments, - }) - } - return config -} - -func generify[T any](generator func() T) examplesGeneratorFunc { - return func() any { return generator() } -} - func errFatal(f string) { fmt.Fprintln(os.Stderr, f) os.Exit(1) } -func mapSlice[T, N any](s []T, m func(T) N) []N { - r := make([]N, len(s)) - for i, v := range s { - r[i] = m(v) +func groupBy[K comparable, V any](s []V, key func(V) K) map[K][]V { + m := make(map[K][]V) + for _, v := range s { + k := key(v) + m[k] = append(m[k], v) } - return r + return m } diff --git a/internal/manifest/v1alpha/examples/alert_method.go b/internal/manifest/v1alpha/examples/alert_method.go index b27fe14f..37faaca9 100644 --- a/internal/manifest/v1alpha/examples/alert_method.go +++ b/internal/manifest/v1alpha/examples/alert_method.go @@ -9,66 +9,87 @@ import ( "github.com/nobl9/nobl9-go/sdk" ) -type alertMethodVariant = string +type alertMethodSpecSubVariant = string const ( - alertMethodVariantWebhookTemplate metricVariant = "template" - alertMethodVariantWebhookTemplateFields metricVariant = "template fields" + alertMethodSpecSubVariantWebhookTemplate metricVariant = "template" + alertMethodSpecSubVariantWebhookTemplateFields metricVariant = "templateFields" ) -var standardAlertMethods = []v1alpha.AlertMethodType{} +var standardAlertMethods = []v1alpha.AlertMethodType{ + v1alpha.AlertMethodTypePagerDuty, + v1alpha.AlertMethodTypeSlack, + v1alpha.AlertMethodTypeDiscord, + v1alpha.AlertMethodTypeOpsgenie, + v1alpha.AlertMethodTypeServiceNow, + v1alpha.AlertMethodTypeJira, + v1alpha.AlertMethodTypeTeams, + v1alpha.AlertMethodTypeEmail, +} -var customAlertMethods = map[v1alpha.AlertMethodType][]alertMethodVariant{ +var customAlertMethodsSubVariants = map[v1alpha.AlertMethodType][]alertMethodSpecSubVariant{ v1alpha.AlertMethodTypeWebhook: { - alertMethodVariantWebhookTemplate, - alertMethodVariantWebhookTemplateFields, + alertMethodSpecSubVariantWebhookTemplate, + alertMethodSpecSubVariantWebhookTemplateFields, }, } -type AlertMethodVariant struct { - Type v1alpha.AlertMethodType - Variant alertMethodVariant +type alertMethodExample struct { + standardExample + methodType v1alpha.AlertMethodType +} - AlertMethod v1alphaAlertMethod.AlertMethod +func (a alertMethodExample) GetYAMLComments() []string { + comment := fmt.Sprintf("%s Alert Method", a.Variant) + if a.SubVariant != "" { + comment += fmt.Sprintf(" with %s", a.SubVariant) + } + return []string{comment} } -func AlertMethod() []AlertMethodVariant { - variants := make([]AlertMethodVariant, 0, len(standardAlertMethods)) +func AlertMethod() []Example { + variants := make([]alertMethodExample, 0, len(standardAlertMethods)) for _, typ := range standardAlertMethods { - variants = append(variants, AlertMethodVariant{ - Type: typ, + variants = append(variants, alertMethodExample{ + standardExample: standardExample{ + Variant: typ.String(), + }, + methodType: typ, }) } - for typ, customVariants := range customAlertMethods { - for _, variant := range customVariants { - variants = append(variants, AlertMethodVariant{ - Type: typ, - Variant: variant, + for typ, subVariants := range customAlertMethodsSubVariants { + for _, subVariant := range subVariants { + variants = append(variants, alertMethodExample{ + standardExample: standardExample{ + Variant: typ.String(), + SubVariant: subVariant, + }, + methodType: typ, }) } } for i := range variants { - variants[i].AlertMethod = variants[i].Generate() + variants[i].Object = variants[i].Generate() } - return variants + return newExampleSlice(variants...) } -func (a AlertMethodVariant) Generate() v1alphaAlertMethod.AlertMethod { +func (a alertMethodExample) Generate() v1alphaAlertMethod.AlertMethod { am := v1alphaAlertMethod.New( v1alphaAlertMethod.Metadata{ - Name: strings.ToLower(a.Type.String()), - DisplayName: a.Type.String() + " Alert Method", + Name: strings.ToLower(a.Variant), + DisplayName: a.Variant + " Alert Method", Project: sdk.DefaultProject, }, v1alphaAlertMethod.Spec{ - Description: fmt.Sprintf("Example %s Alert Method", a.Type), + Description: fmt.Sprintf("Example %s Alert Method", a.Variant), }, ) return a.generateVariant(am) } -func (a AlertMethodVariant) generateVariant(am v1alphaAlertMethod.AlertMethod) v1alphaAlertMethod.AlertMethod { - switch a.Type { +func (a alertMethodExample) generateVariant(am v1alphaAlertMethod.AlertMethod) v1alphaAlertMethod.AlertMethod { + switch a.methodType { case v1alpha.AlertMethodTypeEmail: am.Spec.Email = &v1alphaAlertMethod.EmailAlertMethod{ To: []string{"alerts-tests@nobl9.com"}, @@ -136,8 +157,8 @@ func (a AlertMethodVariant) generateVariant(am v1alphaAlertMethod.AlertMethod) v }, }, } - switch a.Variant { - case alertMethodVariantWebhookTemplate: + switch a.SubVariant { + case alertMethodSpecSubVariantWebhookTemplate: am.Spec.Webhook.Template = ptr(`{ "message": "Your SLO $slo_name needs attention!", "timestamp": "$timestamp", @@ -154,7 +175,7 @@ func (a AlertMethodVariant) generateVariant(am v1alphaAlertMethod.AlertMethod) v "alert_policy": "$alert_policy_labels_text" } }`) - case alertMethodVariantWebhookTemplateFields: + case alertMethodSpecSubVariantWebhookTemplateFields: am.Spec.Webhook.TemplateFields = []string{ "project_name", "service_name", @@ -170,7 +191,7 @@ func (a AlertMethodVariant) generateVariant(am v1alphaAlertMethod.AlertMethod) v } } default: - panic(fmt.Sprintf("unexpected v1alpha.AlertMethodType: %#v", a.Type)) + panic(fmt.Sprintf("unexpected v1alpha.AlertMethodType: %#v", a.Variant)) } return am } diff --git a/internal/manifest/v1alpha/examples/alert_method_test.go b/internal/manifest/v1alpha/examples/alert_method_test.go new file mode 100644 index 00000000..f823b354 --- /dev/null +++ b/internal/manifest/v1alpha/examples/alert_method_test.go @@ -0,0 +1,19 @@ +package v1alphaExamples + +import ( + "slices" + "testing" + + "github.com/nobl9/nobl9-go/manifest/v1alpha" +) + +func TestAlertMethod_SupportsAllAlertMethodTypes(t *testing.T) { + variants := AlertMethod() + for _, methodType := range v1alpha.AlertMethodTypeValues() { + if !slices.ContainsFunc(variants, func(e Example) bool { + return e.(alertMethodExample).methodType == methodType + }) { + t.Errorf("%T '%s' is not listed in the examples", methodType, methodType) + } + } +} diff --git a/internal/manifest/v1alpha/examples/alert_policy.go b/internal/manifest/v1alpha/examples/alert_policy.go new file mode 100644 index 00000000..6bfcdab2 --- /dev/null +++ b/internal/manifest/v1alpha/examples/alert_policy.go @@ -0,0 +1 @@ +package v1alphaExamples diff --git a/internal/manifest/v1alpha/examples/example.go b/internal/manifest/v1alpha/examples/example.go new file mode 100644 index 00000000..98206c6e --- /dev/null +++ b/internal/manifest/v1alpha/examples/example.go @@ -0,0 +1,41 @@ +package v1alphaExamples + +type Example interface { + GetObject() any + GetVariant() string + GetSubVariant() string + GetYAMLComments() []string +} + +func newExampleSlice[T Example](tv ...T) []Example { + examples := make([]Example, 0, len(tv)) + for _, v := range tv { + examples = append(examples, v) + } + return examples +} + +type standardExample struct { + Object any + Variant string + SubVariant string +} + +func (s standardExample) GetObject() any { + return s.Object +} + +func (s standardExample) GetVariant() string { + return s.Variant +} + +func (s standardExample) GetSubVariant() string { + return s.SubVariant +} + +func (s standardExample) GetYAMLComments() []string { + if s.SubVariant == "" { + return nil + } + return []string{s.SubVariant} +} diff --git a/internal/manifest/v1alpha/examples/labels.go b/internal/manifest/v1alpha/examples/labels.go index eb8094bb..d8646c47 100644 --- a/internal/manifest/v1alpha/examples/labels.go +++ b/internal/manifest/v1alpha/examples/labels.go @@ -2,7 +2,13 @@ package v1alphaExamples import "github.com/nobl9/nobl9-go/manifest/v1alpha" -func Labels() v1alpha.Labels { +func Labels() []Example { + return newExampleSlice(standardExample{ + Object: exampleLabels(), + }) +} + +func exampleLabels() v1alpha.Labels { return v1alpha.Labels{ "team": {"green", "sales"}, "env": {"prod", "dev"}, diff --git a/internal/manifest/v1alpha/examples/metadata_annotations.go b/internal/manifest/v1alpha/examples/metadata_annotations.go index 6259659d..ef51e4a7 100644 --- a/internal/manifest/v1alpha/examples/metadata_annotations.go +++ b/internal/manifest/v1alpha/examples/metadata_annotations.go @@ -2,7 +2,13 @@ package v1alphaExamples import "github.com/nobl9/nobl9-go/manifest/v1alpha" -func MetadataAnnotations() v1alpha.MetadataAnnotations { +func MetadataAnnotations() []Example { + return newExampleSlice(standardExample{ + Object: exampleMetadataAnnotations(), + }) +} + +func exampleMetadataAnnotations() v1alpha.MetadataAnnotations { return v1alpha.MetadataAnnotations{ "team": "sales", "env": "prod", diff --git a/internal/manifest/v1alpha/examples/project.go b/internal/manifest/v1alpha/examples/project.go index 0d6b4ffd..53394abf 100644 --- a/internal/manifest/v1alpha/examples/project.go +++ b/internal/manifest/v1alpha/examples/project.go @@ -1,16 +1,20 @@ package v1alphaExamples -import v1alphaProject "github.com/nobl9/nobl9-go/manifest/v1alpha/project" +import ( + v1alphaProject "github.com/nobl9/nobl9-go/manifest/v1alpha/project" +) -func Project() v1alphaProject.Project { - return v1alphaProject.New( - v1alphaProject.Metadata{ - Name: "default", - Labels: Labels(), - Annotations: MetadataAnnotations(), - }, - v1alphaProject.Spec{ - Description: "Example Project", - }, +func Project() []Example { + return newExampleSlice(standardExample{ + Object: v1alphaProject.New( + v1alphaProject.Metadata{ + Name: "default", + Labels: exampleLabels(), + Annotations: exampleMetadataAnnotations(), + }, + v1alphaProject.Spec{ + Description: "Example Project", + }, + )}, ) } diff --git a/internal/manifest/v1alpha/examples/service.go b/internal/manifest/v1alpha/examples/service.go index 1c4444a1..a344adda 100644 --- a/internal/manifest/v1alpha/examples/service.go +++ b/internal/manifest/v1alpha/examples/service.go @@ -4,16 +4,18 @@ import ( v1alphaService "github.com/nobl9/nobl9-go/manifest/v1alpha/service" ) -func Service() v1alphaService.Service { - return v1alphaService.New( - v1alphaService.Metadata{ - Name: "prometheus", - Project: "default", - Labels: Labels(), - Annotations: MetadataAnnotations(), - }, - v1alphaService.Spec{ - Description: "Example Service", - }, +func Service() []Example { + return newExampleSlice(standardExample{ + Object: v1alphaService.New( + v1alphaService.Metadata{ + Name: "prometheus", + Project: "default", + Labels: exampleLabels(), + Annotations: exampleMetadataAnnotations(), + }, + v1alphaService.Spec{ + Description: "Example Service", + }, + )}, ) } diff --git a/internal/manifest/v1alpha/examples/slo.go b/internal/manifest/v1alpha/examples/slo.go index f2506c9e..097c8d1f 100644 --- a/internal/manifest/v1alpha/examples/slo.go +++ b/internal/manifest/v1alpha/examples/slo.go @@ -128,8 +128,8 @@ var badOverTotalVariants = []string{ metricVariantBadRatio, } -func SLO() []SLOVariant { - baseVariants := make([]SLOVariant, 0) +func SLO() []Example { + baseVariants := make([]sloVariant, 0) for _, dataSourceType := range standardGoodOverTotalMetrics { baseVariants = append(baseVariants, createVariants(dataSourceType, goodOverTotalVariants, nil)...) } @@ -145,7 +145,7 @@ func SLO() []SLOVariant { )...) } } - variants := make([]SLOVariant, 0, len(baseVariants)*4) + variants := make([]sloVariant, 0, len(baseVariants)*4) for _, variant := range baseVariants { for _, timeWindow := range []twindow.TimeWindowTypeEnum{ twindow.Rolling, @@ -155,7 +155,7 @@ func SLO() []SLOVariant { v1alphaSLO.BudgetingMethodTimeslices, v1alphaSLO.BudgetingMethodOccurrences, } { - variant = SLOVariant{ + variant = sloVariant{ DataSourceType: variant.DataSourceType, BudgetingMethod: method, TimeWindowType: timeWindow, @@ -167,25 +167,25 @@ func SLO() []SLOVariant { } } } - return variants + return newExampleSlice(variants...) } func createVariants( dataSourceType v1alpha.DataSourceType, metricVariants []metricVariant, metricSubVariants []metricSubVariant, -) []SLOVariant { - variants := make([]SLOVariant, 0, len(metricVariants)*(1+len(metricSubVariants))) +) []sloVariant { + variants := make([]sloVariant, 0, len(metricVariants)*(1+len(metricSubVariants))) for _, variant := range metricVariants { if len(metricSubVariants) == 0 { - variants = append(variants, SLOVariant{ + variants = append(variants, sloVariant{ DataSourceType: dataSourceType, MetricVariant: variant, }) continue } for _, subVariant := range metricSubVariants { - variants = append(variants, SLOVariant{ + variants = append(variants, sloVariant{ DataSourceType: dataSourceType, MetricVariant: variant, MetricSubVariant: subVariant, diff --git a/internal/manifest/v1alpha/examples/slo_test.go b/internal/manifest/v1alpha/examples/slo_test.go index 8efff1d3..02a642ed 100644 --- a/internal/manifest/v1alpha/examples/slo_test.go +++ b/internal/manifest/v1alpha/examples/slo_test.go @@ -10,8 +10,8 @@ import ( func TestSLO_SupportsAllDataSourceTypes(t *testing.T) { variants := SLO() for _, dataSourceType := range v1alpha.DataSourceTypeValues() { - if !slices.ContainsFunc(variants, func(v SLOVariant) bool { - return v.DataSourceType == dataSourceType + if !slices.ContainsFunc(variants, func(e Example) bool { + return e.(sloVariant).DataSourceType == dataSourceType }) { t.Errorf("%T '%s' is not listed in the examples", dataSourceType, dataSourceType) } diff --git a/internal/manifest/v1alpha/examples/slo_variants.go b/internal/manifest/v1alpha/examples/slo_variants.go index ad24f206..1a34db94 100644 --- a/internal/manifest/v1alpha/examples/slo_variants.go +++ b/internal/manifest/v1alpha/examples/slo_variants.go @@ -5,6 +5,7 @@ import ( "fmt" "path/filepath" "reflect" + "slices" "strings" "github.com/nobl9/nobl9-go/manifest" @@ -17,7 +18,7 @@ import ( //go:embed queries var queriesFS embed.FS -type SLOVariant struct { +type sloVariant struct { DataSourceType v1alpha.DataSourceType BudgetingMethod v1alphaSLO.BudgetingMethod TimeWindowType twindow.TimeWindowTypeEnum @@ -27,7 +28,31 @@ type SLOVariant struct { SLO v1alphaSLO.SLO } -func (s SLOVariant) String() string { +func (s sloVariant) GetObject() any { + return s.SLO +} + +func (s sloVariant) GetVariant() string { + return s.DataSourceType.String() +} + +func (s sloVariant) GetSubVariant() string { + return s.String() +} + +func (s sloVariant) GetYAMLComments() []string { + comments := []string{ + fmt.Sprintf(" Metric type: %s", s.MetricVariant), + fmt.Sprintf(" Budgeting method: %s", s.BudgetingMethod), + fmt.Sprintf(" Time window type: %s", s.TimeWindowType), + } + if s.MetricSubVariant != "" { + comments = slices.Insert(comments, 1, fmt.Sprintf(" Metric variant: %s", s.MetricSubVariant)) + } + return comments +} + +func (s sloVariant) String() string { subVariantStr := s.MetricSubVariant if subVariantStr != "" { subVariantStr = subVariantStr + " " @@ -40,17 +65,16 @@ func (s SLOVariant) String() string { s.BudgetingMethod, s.TimeWindowType, ) - } -func (s SLOVariant) Generate() v1alphaSLO.SLO { +func (s sloVariant) Generate() v1alphaSLO.SLO { slo := v1alphaSLO.New( v1alphaSLO.Metadata{ - Name: fmt.Sprintf("api-server-slo"), + Name: "api-server-slo", DisplayName: "API Server SLO", Project: sdk.DefaultProject, - Labels: Labels(), - Annotations: MetadataAnnotations(), + Labels: exampleLabels(), + Annotations: exampleMetadataAnnotations(), }, v1alphaSLO.Spec{ Description: fmt.Sprintf("Example %s SLO", s.DataSourceType), @@ -185,7 +209,7 @@ const ( // The standard variants are: raw, good/total, and bad/total (only supported sources). // If a metric source has non-standard variants (e.g. Lightstep), it can extend metricVariant with it's own types. // It is up to the caller to nil-out the unwanted fields. -func (s SLOVariant) generateMetricVariant(slo v1alphaSLO.SLO) v1alphaSLO.SLO { +func (s sloVariant) generateMetricVariant(slo v1alphaSLO.SLO) v1alphaSLO.SLO { switch s.DataSourceType { case v1alpha.Prometheus: switch s.MetricVariant { diff --git a/internal/manifest/v1alpha/examples/validation_test.go b/internal/manifest/v1alpha/examples/validation_test.go index bec03c99..456ea21b 100644 --- a/internal/manifest/v1alpha/examples/validation_test.go +++ b/internal/manifest/v1alpha/examples/validation_test.go @@ -6,33 +6,48 @@ import ( "github.com/stretchr/testify/assert" "github.com/nobl9/nobl9-go/manifest/v1alpha" + v1alphaAlertMethod "github.com/nobl9/nobl9-go/manifest/v1alpha/alertmethod" + v1alphaProject "github.com/nobl9/nobl9-go/manifest/v1alpha/project" + v1alphaService "github.com/nobl9/nobl9-go/manifest/v1alpha/service" ) func TestExamples_Validate_SLO(t *testing.T) { - variants := SLO() - for _, variant := range variants { - t.Run(variant.String(), func(t *testing.T) { - assert.NoError(t, variant.SLO.Validate()) + for _, variant := range SLO() { + v := variant.(sloVariant) + t.Run(v.String(), func(t *testing.T) { + assert.NoError(t, v.SLO.Validate()) }) } } func TestExamples_Validate_Project(t *testing.T) { - project := Project() - assert.NoError(t, project.Validate()) + for _, variant := range Project() { + assert.NoError(t, variant.GetObject().(v1alphaProject.Project).Validate()) + } } func TestExamples_Validate_Service(t *testing.T) { - service := Service() - assert.NoError(t, service.Validate()) + for _, variant := range Service() { + assert.NoError(t, variant.GetObject().(v1alphaService.Service).Validate()) + } +} + +func TestExamples_Validate_AlertMethods(t *testing.T) { + for _, variant := range AlertMethod() { + assert.NoError(t, variant.GetObject().(v1alphaAlertMethod.AlertMethod).Validate()) + } } func TestExamples_Validate_Labels(t *testing.T) { - labels := Labels() - assert.Nil(t, v1alpha.LabelsValidationRules().Validate(labels)) + for _, variant := range Labels() { + assert.Nil(t, v1alpha.LabelsValidationRules().Validate(variant.GetObject().(v1alpha.Labels))) + } } func TestExamples_Validate_MetadataAnnotations(t *testing.T) { - annotations := MetadataAnnotations() - assert.Nil(t, v1alpha.MetadataAnnotationsValidationRules().Validate(annotations)) + for _, variant := range MetadataAnnotations() { + assert.Nil(t, + v1alpha.MetadataAnnotationsValidationRules(). + Validate(variant.GetObject().(v1alpha.MetadataAnnotations))) + } } diff --git a/manifest/v1alpha/data_sources.go b/manifest/v1alpha/data_sources.go index 30774d17..517f4cd7 100644 --- a/manifest/v1alpha/data_sources.go +++ b/manifest/v1alpha/data_sources.go @@ -64,7 +64,7 @@ type HistoricalDataRetrieval struct { } func HistoricalDataRetrievalValidation() validation.Validator[HistoricalDataRetrieval] { - return validation.New[HistoricalDataRetrieval]( + return validation.New( validation.For(validation.GetSelf[HistoricalDataRetrieval]()). Rules(defaultDataRetrievalDurationValidation), validation.For(func(h HistoricalDataRetrieval) HistoricalRetrievalDuration { return h.MaxDuration }). @@ -78,7 +78,7 @@ func HistoricalDataRetrievalValidation() validation.Validator[HistoricalDataRetr ) } -var historicalRetrievalDurationValidation = validation.New[HistoricalRetrievalDuration]( +var historicalRetrievalDurationValidation = validation.New( validation.ForPointer(func(h HistoricalRetrievalDuration) *int { return h.Value }). WithName("value"). Required(). @@ -129,7 +129,7 @@ var maxQueryDelay = Duration{ } func QueryDelayValidation() validation.Validator[QueryDelay] { - return validation.New[QueryDelay]( + return validation.New( validation.For(func(q QueryDelay) Duration { return q.Duration }). Rules(validation.NewSingleRule(func(d Duration) error { if d.Duration() > maxQueryDelay.Duration() { diff --git a/manifest/v1alpha/labels.go b/manifest/v1alpha/labels.go index 408d2fed..66410068 100644 --- a/manifest/v1alpha/labels.go +++ b/manifest/v1alpha/labels.go @@ -27,7 +27,7 @@ var labelsExamples string var labelKeyRegexp = regexp.MustCompile(`^\p{Ll}([_\-0-9\p{Ll}]*[0-9\p{Ll}])?$`) func LabelsValidationRules() validation.Validator[Labels] { - return validation.New[Labels]( + return validation.New( validation.ForMap(validation.GetSelf[Labels]()). RulesForKeys( validation.StringLength(minLabelKeyLength, maxLabelKeyLength), @@ -38,7 +38,7 @@ func LabelsValidationRules() validation.Validator[Labels] { ) } -var labelValuesValidation = validation.New[[]labelValue]( +var labelValuesValidation = validation.New( validation.ForSlice(validation.GetSelf[[]labelValue]()). Rules(validation.SliceUnique(validation.SelfHashFunc[labelValue]())). RulesForEach( diff --git a/manifest/v1alpha/metadata_annotations.go b/manifest/v1alpha/metadata_annotations.go index bc1ad954..899befa6 100644 --- a/manifest/v1alpha/metadata_annotations.go +++ b/manifest/v1alpha/metadata_annotations.go @@ -28,7 +28,7 @@ var metadataAnnotationsExamples string var annotationKeyRegexp = regexp.MustCompile(`^\p{Ll}([_\-0-9\p{Ll}]*[0-9\p{Ll}])?$`) func MetadataAnnotationsValidationRules() validation.Validator[MetadataAnnotations] { - return validation.New[MetadataAnnotations]( + return validation.New( validation.ForMap(validation.GetSelf[MetadataAnnotations]()). RulesForKeys( validation.StringLength(minAnnotationKeyLength, maxAnnotationKeyLength), @@ -39,7 +39,7 @@ func MetadataAnnotationsValidationRules() validation.Validator[MetadataAnnotatio ) } -var annotationValueValidator = validation.New[annotationValue]( +var annotationValueValidator = validation.New( validation.For(validation.GetSelf[string]()). Rules( validation.StringMaxLength(maxAnnotationValueLength),