diff --git a/examples/check_example/main_test.go b/examples/check_example/main_test.go index c45c515..41db31e 100644 --- a/examples/check_example/main_test.go +++ b/examples/check_example/main_test.go @@ -20,14 +20,14 @@ func TestMyMain(t *testing.T) { expected = "[OK] - value is 10" if !strings.Contains(actual, expected) { - t.Fatalf("expected %v, got %v", expected, actual) + t.Fatalf("expected %q, got %q", expected, actual) } actual = testhelper.RunMainTest(main, "--warning", "10", "--value", "11") expected = "[WARNING] - value is 11" if !strings.Contains(actual, expected) { - t.Fatalf("expected %v, got %v", expected, actual) + t.Fatalf("expected %q\n, got %q", expected, actual) } } diff --git a/examples/check_example2/main.go b/examples/check_example2/main.go index e16813c..8e9ba12 100644 --- a/examples/check_example2/main.go +++ b/examples/check_example2/main.go @@ -11,28 +11,22 @@ func main() { var overall result.Overall - check1 := result.PartialResult{} + check1 := result.NewPartialResult() check1.Output = "Check1" - err := check1.SetState(check.OK) - - if err != nil { - check.ExitError(err) - } + check1.SetState(check.OK) check1.Perfdata.Add(&perfdata.Perfdata{ Label: "foo", Value: 23, }) - check2 := result.PartialResult{} + overall.AddSubcheck(check1) - check2.Output = "Check2" - err = check2.SetState(check.Warning) + check2 := result.NewPartialResult() - if err != nil { - check.ExitError(err) - } + check2.Output = "Check2" + check2.SetState(check.Warning) check2.Perfdata.Add(&perfdata.Perfdata{ Label: "bar", @@ -43,7 +37,6 @@ func main() { Value: 46, }) - overall.AddSubcheck(check1) overall.AddSubcheck(check2) check.Exit(overall.GetStatus(), overall.GetOutput()) diff --git a/examples/check_example2/main_test.go b/examples/check_example2/main_test.go index 55460de..ab97c66 100644 --- a/examples/check_example2/main_test.go +++ b/examples/check_example2/main_test.go @@ -10,7 +10,7 @@ import ( func TestMyMain(t *testing.T) { actual := testhelper.RunMainTest(main) - expected := `[WARNING] - states: warning=1 ok=1 + expected := `[WARNING] - Check2 \_ [OK] Check1 \_ [WARNING] Check2 |foo=23 bar=42 'foo2 bar'=46 @@ -19,7 +19,7 @@ would exit with code 1 ` if actual != expected { - t.Fatalf("expected %v, got %v", expected, actual) + t.Fatalf("expected %q\n, got %q", expected, actual) } } diff --git a/result/overall.go b/result/overall.go index 8aaf300..342ca3d 100644 --- a/result/overall.go +++ b/result/overall.go @@ -1,7 +1,6 @@ package result import ( - "errors" "fmt" "strings" @@ -12,6 +11,14 @@ import ( // The "width" of the indentation which is added on every level const indentationOffset = 2 +// statusCount is used to count the overall states +type statusCount struct { + OK int + Warning int + Critical int + Unknown int +} + // Overall is a singleton for a monitoring plugin that has several partial results (or sub-results) // // Design decisions: A check plugin has a single Overall (singleton), @@ -22,62 +29,16 @@ const indentationOffset = 2 // one suffices, but one fails, the whole check might be OK and only the subcheck // Warning or Critical. type Overall struct { - oks int - warnings int - criticals int - unknowns int - Summary string - stateSetExplicitly bool - Outputs []string // Deprecate this in a future version - PartialResults []PartialResult -} - -// PartialResult represents a sub-result for an Overall struct -type PartialResult struct { - Perfdata perfdata.PerfdataList - PartialResults []PartialResult - Output string - state check.Status // Result state, either set explicitly or derived from partialResults - defaultState check.Status // Default result state, if no partial results are available and no state is set explicitly - stateSetExplicitly bool - defaultStateSet bool -} - -// NewPartialResult initializer with "sane" defaults -// Notable default compared to the nil object: the default state is set to Unknown -func NewPartialResult() PartialResult { - return PartialResult{ - stateSetExplicitly: false, - defaultState: check.Unknown, - } -} - -// String returns the status and output of the PartialResult -func (s *PartialResult) String() string { - return fmt.Sprintf("[%s] %s", s.GetStatus(), s.Output) + OKSummary string + PartialResults []PartialResult } // Add adds a return state explicitly -// -// Hint: This will set stateSetExplicitly to true func (o *Overall) Add(state check.Status, output string) { - switch state { - case check.OK: - o.oks++ - case check.Warning: - o.warnings++ - case check.Critical: - o.criticals++ - case check.Unknown: - o.unknowns++ - default: - o.unknowns++ - } - - // TODO: Might be a bit obscure that the Add method also sets stateSetExplicitly - o.stateSetExplicitly = true - - o.Outputs = append(o.Outputs, fmt.Sprintf("[%s] %s", state, output)) + var result PartialResult + result.SetState(state) + result.Output = output + o.AddSubcheck(result) } // AddSubcheck adds a PartialResult to the Overall @@ -85,129 +46,34 @@ func (o *Overall) AddSubcheck(subcheck PartialResult) { o.PartialResults = append(o.PartialResults, subcheck) } -// AddSubcheck adds a PartialResult to the PartialResult -func (s *PartialResult) AddSubcheck(subcheck PartialResult) { - s.PartialResults = append(s.PartialResults, subcheck) -} - // GetStatus returns the current state (ok, warning, critical, unknown) of the Overall func (o *Overall) GetStatus() check.Status { - if o.stateSetExplicitly { - switch { - case o.criticals > 0: - return check.Critical - case o.unknowns > 0: - return check.Unknown - case o.warnings > 0: - return check.Warning - case o.oks > 0: - return check.OK - default: - return check.Unknown - } - } - - // state not set explicitly! - if len(o.PartialResults) == 0 { - return check.Unknown - } + statuses := o.getStatusCount() - oks, warnings, criticals, unknowns := o.countPartialStates() - - if criticals > 0 { + if statuses.Critical > 0 { return check.Critical } - if unknowns > 0 { + if statuses.Unknown > 0 { return check.Unknown } - if warnings > 0 { + if statuses.Warning > 0 { return check.Warning } - if oks > 0 { + if statuses.OK > 0 { return check.OK } return check.Unknown } -// GetSummary returns a text representation of the current state of the Overall -// nolint: funlen -func (o *Overall) GetSummary() string { - if o.Summary != "" { - return o.Summary - } - - var summary string - - // Was the state set explicitly? - if o.stateSetExplicitly { - // Yes, so lets generate it from the sum of the overall states - if o.criticals > 0 { - summary += fmt.Sprintf("critical=%d ", o.criticals) - } - - if o.unknowns > 0 { - summary += fmt.Sprintf("unknown=%d ", o.unknowns) - } - - if o.warnings > 0 { - summary += fmt.Sprintf("warning=%d ", o.warnings) - } - - if o.oks > 0 { - summary += fmt.Sprintf("ok=%d ", o.oks) - } - - if summary == "" { - o.Summary = "No status information" - return o.Summary - } - } - - if !o.stateSetExplicitly { - // No, so lets combine the partial ones - if len(o.PartialResults) == 0 { - // Oh, we actually don't have those either - o.Summary = "No status information" - return o.Summary - } - - oks, warnings, criticals, unknowns := o.countPartialStates() - - if criticals > 0 { - summary += fmt.Sprintf("critical=%d ", criticals) - } - - if unknowns > 0 { - summary += fmt.Sprintf("unknown=%d ", unknowns) - } - - if warnings > 0 { - summary += fmt.Sprintf("warning=%d ", warnings) - } - - if oks > 0 { - summary += fmt.Sprintf("ok=%d ", oks) - } - } - - o.Summary = "states: " + strings.TrimSpace(summary) - - return o.Summary -} - // GetOutput returns a text representation of the current outputs of the Overall func (o *Overall) GetOutput() string { var output strings.Builder - output.WriteString(o.GetSummary() + "\n") - - for _, extra := range o.Outputs { - output.WriteString(extra + "\n") - } + output.WriteString(o.getSummary() + "\n") if o.PartialResults != nil { var pdata strings.Builder @@ -228,28 +94,83 @@ func (o *Overall) GetOutput() string { return output.String() } -// SetDefaultState sets a new default state for a PartialResult -func (s *PartialResult) SetDefaultState(state check.Status) error { - if state < check.OK || state > check.Unknown { - return errors.New("Default State is not a valid result state. Got " + state.String() + " which is not valid") +func (o *Overall) getStatusCount() statusCount { + result := statusCount{ + OK: 0, + Warning: 0, + Critical: 0, + Unknown: 0, } - s.defaultState = state - s.defaultStateSet = true + if len(o.PartialResults) == 0 { + return result + } + + for _, sc := range o.PartialResults { + switch sc.GetStatus() { + case check.Critical: + result.Critical++ + case check.Warning: + result.Warning++ + case check.Unknown: + result.Unknown++ + case check.OK: + result.OK++ + } + } - return nil + return result } -// SetState sets a state for a PartialResult -func (s *PartialResult) SetState(state check.Status) error { - if state < check.OK || state > check.Unknown { - return errors.New("State is not a valid result state. Got " + state.String() + " which is not valid") +// PartialResult represents a sub-result for an Overall struct +type PartialResult struct { + Perfdata perfdata.PerfdataList + PartialResults []PartialResult + Output string + + // Result state, either set explicitly or derived from partialResults + state check.Status + // Default result state, if no partial results are available and no state is set explicitly + defaultState check.Status + + // stateSetExplicitly indicates that SetState was called directly. When true, + // GetStatus returns s.state unconditionally, bypassing PartialResults entirely. + stateSetExplicitly bool + // defaultStateSetExplicitly indicates that SetDefaultState was called. When true + // and no PartialResults exist and no explicit state is set, GetStatus returns + // s.defaultState instead of check.Unknown. + defaultStateSetExplicitly bool +} + +// NewPartialResult initializer with defaults. It is recommended to use NewPartialResult. +// The default compared to the nil object is the default state is set to Unknown. +func NewPartialResult() PartialResult { + return PartialResult{ + stateSetExplicitly: false, + defaultState: check.Unknown, } +} + +// AddSubcheck adds a PartialResult to the PartialResult +func (s *PartialResult) AddSubcheck(subcheck PartialResult) { + s.PartialResults = append(s.PartialResults, subcheck) +} + +// String returns the status and output of the PartialResult +func (s *PartialResult) String() string { + return fmt.Sprintf("[%s] %s", s.GetStatus(), s.Output) +} + +// SetDefaultState sets a new default state for a PartialResult +func (s *PartialResult) SetDefaultState(state check.Status) { + s.defaultState = state + s.defaultStateSetExplicitly = true +} +// SetState sets a state for a PartialResult +func (s *PartialResult) SetState(state check.Status) { s.state = state s.stateSetExplicitly = true - - return nil } // GetStatus returns the current state (ok, warning, critical, unknown) of the PartialResult @@ -259,7 +180,7 @@ func (s *PartialResult) GetStatus() check.Status { } if len(s.PartialResults) == 0 { - if s.defaultStateSet { + if s.defaultStateSetExplicitly { return s.defaultState } @@ -275,24 +196,6 @@ func (s *PartialResult) GetStatus() check.Status { return WorstState(states...) } -// countPartialStates returns the current count of states -func (o *Overall) countPartialStates() (oks, warnings, criticals, unknowns int) { - for _, sc := range o.PartialResults { - switch sc.GetStatus() { - case check.Critical: - criticals++ - case check.Warning: - warnings++ - case check.Unknown: - unknowns++ - case check.OK: - oks++ - } - } - - return -} - // getPerfdata returns all subsequent perfdata as a concatenated string func (s *PartialResult) getPerfdata() string { var output strings.Builder @@ -313,12 +216,10 @@ func (s *PartialResult) getPerfdata() string { // getOutput generates indented output for all subsequent PartialResults func (s *PartialResult) getOutput(indentLevel int) string { var output strings.Builder - - prefix := strings.Repeat(" ", indentLevel) // The final result will look like this: // [OK] Overall is OK // \_ [OK] My PartialResult - output.WriteString(prefix + "\\_ " + s.String() + "\n") + output.WriteString(strings.Repeat(" ", indentLevel) + "\\_ " + s.String() + "\n") if s.PartialResults != nil { for _, ss := range s.PartialResults { @@ -328,3 +229,82 @@ func (s *PartialResult) getOutput(indentLevel int) string { return output.String() } + +// GetSummary returns a text representation of the current state of the Overall +func (o *Overall) getSummary() string { + checkState := o.GetStatus() + + if checkState == check.OK && o.OKSummary != "" { + return o.OKSummary + } + + if len(o.PartialResults) == 0 { + // Oh, we actually don't have those either + return "No status information" + } + + if checkState == check.OK { + return o.getGenericSummary() + } + + // Non-OK result + // get worst-first non-ok PartialResults output + result := "" + worstState := check.OK + + for _, partRes := range o.PartialResults { + if check.Compare(worstState, partRes.GetStatus()) > 0 { + result = partRes.getPartialResultFailedOutput() + } + } + + if result == "" { + // No output in PartialResults ... + result = o.getGenericSummary() + } + + return result +} + +func (o *Overall) getGenericSummary() string { + stats := o.getStatusCount() + result := "" + + if stats.Critical > 0 { + result += fmt.Sprintf("critical=%d ", stats.Critical) + } + + if stats.Unknown > 0 { + result += fmt.Sprintf("unknown=%d ", stats.Unknown) + } + + if stats.Warning > 0 { + result += fmt.Sprintf("warning=%d ", stats.Warning) + } + + if stats.OK > 0 { + result += fmt.Sprintf("ok=%d ", stats.OK) + } + + result = "states: " + strings.TrimSpace(result) + + return result +} + +func (s *PartialResult) getPartialResultFailedOutput() string { + if len(s.PartialResults) == 0 { + // this is a leave node + return s.Output + } + + worstState := check.OK + result := "" + + for _, partRes := range s.PartialResults { + if check.Compare(worstState, partRes.GetStatus()) > 0 { + result = partRes.getPartialResultFailedOutput() + } + } + + return result +} diff --git a/result/overall_test.go b/result/overall_test.go index a06ba78..b3fbd7a 100644 --- a/result/overall_test.go +++ b/result/overall_test.go @@ -21,13 +21,15 @@ func TestOverall_AddOK(t *testing.T) { overall := Overall{} overall.Add(0, "test ok") - if overall.oks != 1 { - t.Fatalf("expected 1, got %d", overall.oks) + counts := overall.getStatusCount() + + if counts.OK != 1 && counts.Critical != 0 && counts.Warning != 0 && counts.Unknown != 0 { + t.Fatalf("expected 1, got %d", counts.OK) } - expectedOutputs := []string{"[OK] test ok"} - if !reflect.DeepEqual(overall.Outputs, expectedOutputs) { - t.Fatalf("expected %v, got %v", expectedOutputs, overall.Outputs) + expectedOutput := "states: ok=1\n\\_ [OK] test ok\n" + if !reflect.DeepEqual(overall.GetOutput(), expectedOutput) { + t.Fatalf("expected \n%q\n, got \n%q\n", expectedOutput, overall.GetOutput()) } } @@ -35,13 +37,15 @@ func TestOverall_AddWarning(t *testing.T) { overall := Overall{} overall.Add(1, "test warning") - if overall.warnings != 1 { - t.Fatalf("expected 1, got %d", overall.warnings) + counts := overall.getStatusCount() + + if counts.OK != 0 && counts.Critical != 0 && counts.Warning != 1 && counts.Unknown != 0 { + t.Fatalf("expected 1, got %d", counts.Warning) } - expectedOutputs := []string{"[WARNING] test warning"} - if !reflect.DeepEqual(overall.Outputs, expectedOutputs) { - t.Fatalf("expected %v, got %v", expectedOutputs, overall.Outputs) + expectedOutput := "test warning\n\\_ [WARNING] test warning\n" + if !reflect.DeepEqual(overall.GetOutput(), expectedOutput) { + t.Fatalf("expected %q\n, got %q", expectedOutput, overall.GetOutput()) } } @@ -49,13 +53,15 @@ func TestOverall_AddCritical(t *testing.T) { overall := Overall{} overall.Add(2, "test critical") - if overall.criticals != 1 { - t.Fatalf("expected 1, got %d", overall.criticals) + counts := overall.getStatusCount() + + if counts.OK != 0 && counts.Critical != 1 && counts.Warning != 0 && counts.Unknown != 0 { + t.Fatalf("expected 1, got %d", counts.Critical) } - expectedOutputs := []string{"[CRITICAL] test critical"} - if !reflect.DeepEqual(overall.Outputs, expectedOutputs) { - t.Fatalf("expected %v, got %v", expectedOutputs, overall.Outputs) + expectedOutputs := "test critical\n\\_ [CRITICAL] test critical\n" + if !reflect.DeepEqual(overall.GetOutput(), expectedOutputs) { + t.Fatalf("expected %q, got %q", expectedOutputs, overall.GetOutput()) } } @@ -63,64 +69,15 @@ func TestOverall_AddUnknown(t *testing.T) { overall := Overall{} overall.Add(3, "test unknown") - if overall.unknowns != 1 { - t.Fatalf("expected 1, got %d", overall.unknowns) - } - - expectedOutputs := []string{"[UNKNOWN] test unknown"} - if !reflect.DeepEqual(overall.Outputs, expectedOutputs) { - t.Fatalf("expected %v, got %v", expectedOutputs, overall.Outputs) - } -} + counts := overall.getStatusCount() -func TestOverall_GetStatus_GetSummary(t *testing.T) { - testcases := map[string]struct { - actual Overall - expectedSummary string - expectedStatus check.Status - }{ - "No status information": { - actual: Overall{}, - expectedSummary: "No status information", - expectedStatus: check.Unknown, - }, - "states: ok=1": { - actual: Overall{oks: 1, stateSetExplicitly: true}, - expectedSummary: "states: ok=1", - expectedStatus: check.OK, - }, - "states: critical=2 unknown=1 warning=2 ok=1": { - actual: Overall{criticals: 2, oks: 1, warnings: 2, unknowns: 1, stateSetExplicitly: true}, - expectedSummary: "states: critical=2 unknown=1 warning=2 ok=1", - expectedStatus: check.Critical, - }, - "states: unknown=2 warning=2 ok=1": { - actual: Overall{unknowns: 2, oks: 1, warnings: 2, stateSetExplicitly: true}, - expectedSummary: "states: unknown=2 warning=2 ok=1", - expectedStatus: check.Unknown, - }, - "states: warning=2 ok=1": { - actual: Overall{oks: 1, warnings: 2, stateSetExplicitly: true}, - expectedSummary: "states: warning=2 ok=1", - expectedStatus: check.Warning, - }, - "foobar": { - actual: Overall{Summary: "foobar"}, - expectedSummary: "foobar", - expectedStatus: check.Unknown, - }, + if counts.OK != 0 && counts.Critical != 0 && counts.Warning != 0 && counts.Unknown != 1 { + t.Fatalf("expected 1, got %d", counts.Unknown) } - for name, test := range testcases { - t.Run(name, func(t *testing.T) { - if test.expectedSummary != test.actual.GetSummary() { - t.Fatalf("expected summary %s, got %s", test.expectedSummary, test.actual.GetSummary()) - } - - if test.expectedStatus != test.actual.GetStatus() { - t.Fatalf("expected status %d, got %d", test.expectedStatus, test.actual.GetStatus()) - } - }) + expectedOutputs := "test unknown\n\\_ [UNKNOWN] test unknown\n" + if !reflect.DeepEqual(overall.GetOutput(), expectedOutputs) { + t.Fatalf("expected %q, got %q", expectedOutputs, overall.GetOutput()) } } @@ -131,31 +88,31 @@ func TestOverall_GetOutput(t *testing.T) { overall.Add(0, "First OK") overall.Add(0, "Second OK") - expected := "states: ok=2\n[OK] First OK\n[OK] Second OK\n" + expected := "states: ok=2\n\\_ [OK] First OK\n\\_ [OK] Second OK\n" if expected != overall.GetOutput() { - t.Fatalf("expected %s, got %s", expected, overall.GetOutput()) + t.Fatalf("expected %q, got %q", expected, overall.GetOutput()) } overall = Overall{} overall.Add(0, "State OK") - expected = "states: ok=1\n[OK] State OK\n" + expected = "states: ok=1\n\\_ [OK] State OK\n" if expected != overall.GetOutput() { - t.Fatalf("expected %s, got %s", expected, overall.GetOutput()) + t.Fatalf("expected %q, got %q", expected, overall.GetOutput()) } // TODO: compress when only one state overall = Overall{} overall.Add(0, "First OK") overall.Add(2, "Second Critical") - overall.Summary = "Custom Summary" + overall.OKSummary = "Custom Summary" - expected = "Custom Summary\n[OK] First OK\n[CRITICAL] Second Critical\n" + expected = "Second Critical\n\\_ [OK] First OK\n\\_ [CRITICAL] Second Critical\n" if expected != overall.GetOutput() { - t.Fatalf("expected %s, got %s", expected, overall.GetOutput()) + t.Fatalf("expected %q, got %q", expected, overall.GetOutput()) } } @@ -164,8 +121,7 @@ func ExampleOverall_Add() { overall.Add(check.OK, "One element is good") overall.Add(check.Critical, "The other is critical") - fmt.Printf("%#v\n", overall) - // Output: result.Overall{oks:1, warnings:0, criticals:1, unknowns:0, Summary:"", stateSetExplicitly:true, Outputs:[]string{"[OK] One element is good", "[CRITICAL] The other is critical"}, PartialResults:[]result.PartialResult(nil)} + fmt.Printf("%s", overall.GetOutput()) } func ExampleOverall_GetOutput() { @@ -175,9 +131,9 @@ func ExampleOverall_GetOutput() { fmt.Println(overall.GetOutput()) // Output: - // states: critical=1 ok=1 - // [OK] One element is good - // [CRITICAL] The other is critical + // The other is critical + // \_ [OK] One element is good + // \_ [CRITICAL] The other is critical } func ExampleOverall_GetStatus() { @@ -204,13 +160,13 @@ func ExampleOverall_withSubchecks() { subcheck.SetState(check.OK) overall.AddSubcheck(subcheck) - overall.Add(0, "bla") + overall.Add(check.OK, "bla") fmt.Println(overall.GetOutput()) // Output: - // states: ok=1 - // [OK] bla + // states: ok=2 // \_ [OK] Subcheck1 Test + // \_ [OK] bla // |pd_test=5s } @@ -256,7 +212,7 @@ func TestOverall_withEnhancedSubchecks(t *testing.T) { resString := overall.GetOutput() - expectedString := `states: warning=1 ok=1 + expectedString := `Subcheck2 Test \_ [OK] Subcheck1 Test \_ [WARNING] Subcheck2 Test |pd_test=5s pd_test2=1099511627776kB;@3.14:7036874417766;549755813887:1208925819614629174706176;;18446744073709551615 kl;jr2if;l2rkjasdf=5m asdf=18446744073709551615B @@ -388,7 +344,7 @@ func TestOverall_withSubchecks_PartialResult(t *testing.T) { overall.AddSubcheck(subcheck) - res := `states: critical=1 + res := `SubSubSubcheck \_ [CRITICAL] PartialResult \_ [CRITICAL] SubSubcheck \_ [CRITICAL] SubSubSubcheck @@ -478,7 +434,7 @@ func TestSubchecksPerfdata(t *testing.T) { overall.AddSubcheck(check1) overall.AddSubcheck(check2) - resultString := "states: warning=1 ok=1\n\\_ [OK] Check1\n\\_ [WARNING] Check2\n|foo=23 bar=42 'foo2 bar'=46\n" + resultString := "Check2\n\\_ [OK] Check1\n\\_ [WARNING] Check2\n|foo=23 bar=42 'foo2 bar'=46\n" if resultString != overall.GetOutput() { t.Fatalf("expected %s, got %s", resultString, overall.GetOutput()) diff --git a/result/worst.go b/result/worst.go index df57fd5..099f273 100644 --- a/result/worst.go +++ b/result/worst.go @@ -17,18 +17,12 @@ func WorstState(states ...check.Status) check.Status { // nolint: gocritic for _, state := range states { - if state == check.Critical { - overall = check.Critical - } else if state == check.Unknown { - if overall != check.Critical { - overall = check.Unknown - } - } else if state > overall { + if check.Compare(overall, state) > 0 { overall = state } } - if overall < 0 || overall > 3 { + if overall < check.OK || overall > check.Unknown { overall = check.Unknown } diff --git a/status.go b/status.go index 8f1c237..849161d 100644 --- a/status.go +++ b/status.go @@ -76,3 +76,43 @@ func (s Status) String() string { return UnknownString } } + +func Compare(a Status, b Status) int { + switch a { + case OK: + switch b { + case OK: + return 0 + case Warning, Unknown, Critical: + return 1 + } + case Warning: + switch b { + case OK: + return -1 + case Warning: + return 0 + case Unknown, Critical: + return 1 + } + case Unknown: + switch b { + case OK, Warning: + return -1 + case Unknown: + return 0 + case Critical: + return 1 + } + case Critical: + switch b { + case OK, Warning, Unknown: + return -1 + case Critical: + return 0 + } + } + + // should not be possible to land here + return 0 +} diff --git a/status_test.go b/status_test.go index 7af29f2..f56340c 100644 --- a/status_test.go +++ b/status_test.go @@ -141,3 +141,20 @@ func TestStatus_FromInt_WithErr(t *testing.T) { t.Fatalf("expected Unknown, got %v", actual) } } + +func TestCompareStatus(t *testing.T) { + inputList := []Status{OK, Warning, Unknown, Critical} + + for _, val := range inputList { + if Compare(val, val) != 0 { + t.Fatalf("Equal comparison failed with %d and %d", val, val) + } + } + + if Compare(OK, Warning) <= 0 { + t.Fatalf("Comparison failed with OK and Warning, got %d", Compare(OK, Warning)) + } + if Compare(Warning, OK) >= 0 { + t.Fatalf("Comparison failed with OK and Warning, got %d", Compare(Warning, OK)) + } +}