package checker import ( "encoding/json" "testing" "time" sdk "git.happydns.org/checker-sdk-go/checker" ) type fakeReportCtx struct { data json.RawMessage } func (f fakeReportCtx) Data() json.RawMessage { return f.data } func (fakeReportCtx) Related(sdk.ObservationKey) []sdk.RelatedObservation { return nil } func (fakeReportCtx) States() []sdk.CheckState { return nil } func TestProviderKey(t *testing.T) { p := Provider() if p.Key() != ObservationKeyHappyDeliver { t.Errorf("Key = %q", p.Key()) } } func TestProviderImplementsMetricsReporter(t *testing.T) { if _, ok := Provider().(sdk.CheckerMetricsReporter); !ok { t.Fatal("provider should implement CheckerMetricsReporter") } } func TestExtractMetrics(t *testing.T) { d := HappyDeliverData{ Phase: "ok", Scores: map[string]int{ SectionOverall: 88, SectionDNS: 90, SectionAuthentication: 70, }, } raw, _ := json.Marshal(d) now := time.Now() metrics, err := Provider().(sdk.CheckerMetricsReporter).ExtractMetrics(fakeReportCtx{data: raw}, now) if err != nil { t.Fatal(err) } if len(metrics) != 3 { t.Fatalf("expected 3 metrics, got %d", len(metrics)) } // Order must match AllSections (overall first). if metrics[0].Labels["section"] != SectionOverall || metrics[0].Value != 88 { t.Errorf("metrics[0] = %+v", metrics[0]) } for _, m := range metrics { if m.Name != "happydeliver_score" { t.Errorf("name = %q", m.Name) } if m.Unit != "points" { t.Errorf("unit = %q", m.Unit) } if !m.Timestamp.Equal(now) { t.Errorf("ts = %v", m.Timestamp) } } } func TestExtractMetricsNoScores(t *testing.T) { d := HappyDeliverData{Phase: "send", Error: "x"} raw, _ := json.Marshal(d) metrics, err := Provider().(sdk.CheckerMetricsReporter).ExtractMetrics(fakeReportCtx{data: raw}, time.Now()) if err != nil { t.Fatal(err) } if metrics != nil { t.Errorf("expected nil metrics, got %v", metrics) } } func TestExtractMetricsBadPayload(t *testing.T) { _, err := Provider().(sdk.CheckerMetricsReporter).ExtractMetrics(fakeReportCtx{data: []byte("garbage")}, time.Now()) if err == nil { t.Fatal("expected error on bad JSON") } } func TestDefinitionShape(t *testing.T) { def := Definition() if def.ID != "happydeliver" { t.Errorf("ID = %q", def.ID) } if !def.Availability.ApplyToDomain { t.Error("should apply to domain") } if !def.HasMetrics { t.Error("HasMetrics should be true") } // Section rules + lifecycle rule. if got, want := len(def.Rules), len(AllSections)+1; got != want { t.Errorf("rule count = %d, want %d", got, want) } // Each section must have a corresponding rule named happydeliver.score.
. have := map[string]bool{} for _, r := range def.Rules { have[r.Name()] = true } for _, s := range AllSections { if !have["happydeliver.score."+s] { t.Errorf("missing rule for section %q", s) } } if !have["happydeliver.lifecycle"] { t.Error("missing lifecycle rule") } if def.Interval == nil || def.Interval.Default != 7*24*time.Hour { t.Errorf("interval = %+v", def.Interval) } } func TestDefinitionBuildRulesInfo(t *testing.T) { def := Definition() def.BuildRulesInfo() if len(def.RulesInfo) != len(def.Rules) { t.Fatalf("RulesInfo len = %d, want %d", len(def.RulesInfo), len(def.Rules)) } // Section rules expose Options(); the lifecycle rule does not. var withOpts, withoutOpts int for _, info := range def.RulesInfo { if info.Options != nil { withOpts++ } else { withoutOpts++ } } if withOpts != len(AllSections) { t.Errorf("rules-with-options = %d, want %d", withOpts, len(AllSections)) } if withoutOpts != 1 { t.Errorf("rules-without-options = %d, want 1 (lifecycle)", withoutOpts) } }