diff --git a/examples/check_example2/main.go b/examples/check_example2/main.go index ccba7dc..6a20710 100644 --- a/examples/check_example2/main.go +++ b/examples/check_example2/main.go @@ -12,10 +12,10 @@ func main() { check1 := result.NewPartialResult() - check1.Output = "Check1" + check1.SetOutput("Check1") check1.SetState(check.OK) - check1.Perfdata.Add(&check.Perfdata{ + check1.AddPerfdata(&check.Perfdata{ Label: "foo", Value: 23, }) @@ -24,14 +24,14 @@ func main() { check2 := result.NewPartialResult() - check2.Output = "Check2" + check2.SetOutput("Check2") check2.SetState(check.Warning) - check2.Perfdata.Add(&check.Perfdata{ + check2.AddPerfdata(&check.Perfdata{ Label: "bar", Value: 42, }) - check2.Perfdata.Add(&check.Perfdata{ + check2.AddPerfdata(&check.Perfdata{ Label: "foo2 bar", Value: 46, }) diff --git a/result/overall.go b/result/overall.go index 4861c25..87f6c9c 100644 --- a/result/overall.go +++ b/result/overall.go @@ -31,9 +31,9 @@ type statusCount struct { // Warning or Critical. type Overall struct { // default summary (first line of output) if everything is ok. Has to be set in a plugin - OKSummary string + oKSummary string // The results that are associated with this overall - PartialResults []*PartialResult + partialResults []*PartialResult // We use a Mutex to make sure PartialResults can be added and evaluated concurrently mu sync.RWMutex @@ -44,7 +44,7 @@ type Overall struct { func (o *Overall) Add(state check.Status, output string) { var result PartialResult result.SetState(state) - result.Output = output + result.SetOutput(output) o.AddSubcheck(&result) } @@ -54,7 +54,7 @@ func (o *Overall) AddSubcheck(subcheck *PartialResult) { o.mu.Lock() defer o.mu.Unlock() - o.PartialResults = append(o.PartialResults, subcheck) + o.partialResults = append(o.partialResults, subcheck) } // GetStatus returns the current state (ok, warning, critical, unknown) of the Overall. @@ -94,13 +94,13 @@ func (o *Overall) GetOutput() string { output.WriteString(o.getSummary() + "\n") - if o.PartialResults != nil { + if o.partialResults != nil { var pdata strings.Builder // Generate indeted output and perfdata for all partialResults - for i := range o.PartialResults { - output.WriteString(strings.ReplaceAll(o.PartialResults[i].getOutput(0), check.PerfdataSeparatorSymbol, " ")) - pdata.WriteString(" " + o.PartialResults[i].getPerfdata()) + for i := range o.partialResults { + output.WriteString(strings.ReplaceAll(o.partialResults[i].getOutput(0), check.PerfdataSeparatorSymbol, " ")) + pdata.WriteString(" " + o.partialResults[i].getPerfdata()) } pdataString := strings.Trim(pdata.String(), " ") @@ -113,6 +113,14 @@ func (o *Overall) GetOutput() string { return output.String() } +// SetOKSummary sets the summary to the given string +func (o *Overall) SetOKSummary(summary string) { + o.mu.Lock() + defer o.mu.Unlock() + + o.oKSummary = summary +} + func (o *Overall) getStatusCount() statusCount { result := statusCount{ OK: 0, @@ -121,11 +129,11 @@ func (o *Overall) getStatusCount() statusCount { Unknown: 0, } - if len(o.PartialResults) == 0 { + if len(o.partialResults) == 0 { return result } - for _, sc := range o.PartialResults { + for _, sc := range o.partialResults { switch sc.GetStatus() { case check.Critical: result.Critical++ @@ -141,137 +149,15 @@ func (o *Overall) getStatusCount() statusCount { return result } -// PartialResult represents a sub-result for an Overall struct -type PartialResult struct { - Perfdata check.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 - - mu sync.RWMutex -} - -// 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.mu.Lock() - defer s.mu.Unlock() - - 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(), strings.ReplaceAll(s.Output, check.PerfdataSeparatorSymbol, " ")) -} - -// SetDefaultState sets a new default state for a PartialResult -func (s *PartialResult) SetDefaultState(state check.Status) { - s.mu.Lock() - defer s.mu.Unlock() - - s.defaultState = state - s.defaultStateSetExplicitly = true -} - -// SetState sets a state for a PartialResult -func (s *PartialResult) SetState(state check.Status) { - s.mu.Lock() - defer s.mu.Unlock() - - s.state = state - s.stateSetExplicitly = true -} - -// GetStatus returns the current state (ok, warning, critical, unknown) of the PartialResult -func (s *PartialResult) GetStatus() check.Status { - s.mu.RLock() - defer s.mu.RUnlock() - - if s.stateSetExplicitly { - return s.state - } - - if len(s.PartialResults) == 0 { - if s.defaultStateSetExplicitly { - return s.defaultState - } - - return check.Unknown - } - - states := make([]check.Status, len(s.PartialResults)) - - for i := range s.PartialResults { - states[i] = s.PartialResults[i].GetStatus() - } - - return check.WorstState(states...) -} - -// getPerfdata returns all subsequent perfdata as a concatenated string -func (s *PartialResult) getPerfdata() string { - var output strings.Builder - - if len(s.Perfdata) > 0 { - output.WriteString(s.Perfdata.String()) - } - - if s.PartialResults != nil { - for _, ss := range s.PartialResults { - output.WriteString(" " + ss.getPerfdata()) - } - } - - return strings.TrimSpace(output.String()) -} - -// getOutput generates indented output for all subsequent PartialResults -func (s *PartialResult) getOutput(indentLevel int) string { - var output strings.Builder - // The final result will look like this: - // [OK] Overall is OK - // \_ [OK] My PartialResult - output.WriteString(strings.Repeat(" ", indentLevel) + "\\_ " + s.String() + "\n") - - if s.PartialResults != nil { - for _, ss := range s.PartialResults { - output.WriteString(ss.getOutput(indentLevel + indentationOffset)) - } - } - - 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 strings.ReplaceAll(o.OKSummary, check.PerfdataSeparatorSymbol, " ") + if checkState == check.OK && o.oKSummary != "" { + return strings.ReplaceAll(o.oKSummary, check.PerfdataSeparatorSymbol, " ") } - if len(o.PartialResults) == 0 { + if len(o.partialResults) == 0 { // Oh, we actually don't have those either return "No status information" } @@ -284,7 +170,7 @@ func (o *Overall) getSummary() string { worstState := check.OK // Get the worst non-ok PartialResults output - for _, partRes := range o.PartialResults { + for _, partRes := range o.partialResults { if check.Compare(worstState, partRes.GetStatus()) > 0 { result = partRes.getPartialResultFailedOutput() worstState = partRes.GetStatus() @@ -323,23 +209,3 @@ func (o *Overall) getGenericSummary() string { return result } - -func (s *PartialResult) getPartialResultFailedOutput() string { - if len(s.PartialResults) == 0 { - // this is a leave node - return s.Output - } - - result := "" - worstState := check.OK - - // Get the worst non-ok PartialResults output - for _, partRes := range s.PartialResults { - if check.Compare(worstState, partRes.GetStatus()) > 0 { - result = partRes.getPartialResultFailedOutput() - worstState = partRes.GetStatus() - } - } - - return result -} diff --git a/result/overall_test.go b/result/overall_test.go index 371c074..7e65617 100644 --- a/result/overall_test.go +++ b/result/overall_test.go @@ -10,14 +10,6 @@ import ( "github.com/NETWAYS/go-check" ) -func TestOverall_NewPartialResult(t *testing.T) { - actual := NewPartialResult() - - if actual.String() != "[UNKNOWN] " { - t.Fatalf("expected '[UNKNOWN] ', got %s", actual.String()) - } -} - func TestOverall_AddOK(t *testing.T) { overall := Overall{} overall.Add(0, "test ok") @@ -108,7 +100,7 @@ func TestOverall_GetOutput(t *testing.T) { overall = Overall{} overall.Add(0, "First OK") overall.Add(2, "Second Critical") - overall.OKSummary = "Custom Summary" + overall.oKSummary = "Custom Summary" expected = "Second Critical\n\\_ [OK] First OK\n\\_ [CRITICAL] Second Critical\n" @@ -149,14 +141,11 @@ func ExampleOverall_GetStatus() { func ExampleOverall_withSubchecks() { var overall Overall - example_perfdata := check.Perfdata{Label: "pd_test", Value: 5, Uom: "s"} - pd_list := check.PerfdataList{} - pd_list.Add(&example_perfdata) + subcheck := NewPartialResult() + subcheck.SetOutput("Subcheck1 Test") - subcheck := &PartialResult{ - Output: "Subcheck1 Test", - Perfdata: pd_list, - } + example_perfdata := check.Perfdata{Label: "pd_test", Value: 5, Uom: "s"} + subcheck.AddPerfdata(&example_perfdata) subcheck.SetState(check.OK) @@ -174,17 +163,15 @@ func ExampleOverall_withSubchecks() { func ExampleOverall_withVerticalbar() { var overall Overall - overall.OKSummary = "unit|test" - - example_perfdata := check.Perfdata{Label: "pd_test", Value: 5, Uom: "s"} - pd_list := check.PerfdataList{} - pd_list.Add(&example_perfdata) + overall.oKSummary = "unit|test" subcheck := &PartialResult{ - Output: "vertical|bar", - Perfdata: pd_list, + output: "vertical|bar", } + example_perfdata := check.Perfdata{Label: "pd_test", Value: 5, Uom: "s"} + subcheck.AddPerfdata(&example_perfdata) + subcheck.SetState(check.OK) overall.AddSubcheck(subcheck) @@ -213,25 +200,19 @@ func TestOverall_withEnhancedSubchecks(t *testing.T) { example_perfdata3 := check.Perfdata{Label: "kl;jr2if;l2rkjasdf", Value: 5, Uom: "m"} example_perfdata4 := check.Perfdata{Label: "asdf", Value: uint64(18446744073709551615), Uom: "B"} - pd_list := check.PerfdataList{} - pd_list.Add(&example_perfdata) - pd_list.Add(&example_perfdata2) - - pd_list2 := check.PerfdataList{} - pd_list2.Add(&example_perfdata3) - pd_list2.Add(&example_perfdata4) + subcheck := NewPartialResult() + subcheck.SetOutput("Subcheck1 Test") - subcheck := &PartialResult{ - Output: "Subcheck1 Test", - Perfdata: pd_list, - } + subcheck.AddPerfdata(&example_perfdata) + subcheck.AddPerfdata(&example_perfdata2) subcheck.SetState(check.OK) - subcheck2 := &PartialResult{ - Output: "Subcheck2 Test", - Perfdata: pd_list2, - } + subcheck2 := NewPartialResult() + subcheck2.SetOutput("Subcheck2 Test") + + subcheck2.AddPerfdata(&example_perfdata3) + subcheck2.AddPerfdata(&example_perfdata4) subcheck2.SetState(check.Warning) @@ -258,19 +239,17 @@ func TestOverall_withEnhancedSubchecks(t *testing.T) { func TestOverall_withSubchecks_Simple_Output(t *testing.T) { var overall Overall - subcheck2 := &PartialResult{ - Output: "SubSubcheck", - } + subcheck2 := NewPartialResult() + subcheck2.SetOutput("SubSubcheck") subcheck2.SetState(check.OK) - subcheck := &PartialResult{ - Output: "PartialResult", - } + subcheck := NewPartialResult() + subcheck.SetOutput("PartialResult") subcheck.SetState(check.OK) - subcheck.PartialResults = append(subcheck.PartialResults, subcheck2) + subcheck.AddSubcheck(subcheck2) overall.AddSubcheck(subcheck) @@ -289,15 +268,13 @@ func TestOverall_withSubchecks_Simple_Output(t *testing.T) { func TestOverall_withSubchecks_Perfdata(t *testing.T) { var overall Overall - subcheck2 := &PartialResult{ - Output: "SubSubcheck", - } + subcheck2 := NewPartialResult() + subcheck2.SetOutput("SubSubcheck") subcheck2.SetState(check.OK) - subcheck := &PartialResult{ - Output: "PartialResult", - } + subcheck := NewPartialResult() + subcheck.SetOutput("PartialResult") subcheck.SetState(check.OK) @@ -311,9 +288,9 @@ func TestOverall_withSubchecks_Perfdata(t *testing.T) { Uom: "%", } - subcheck2.Perfdata.Add(&perf1) - subcheck2.Perfdata.Add(&perf2) - subcheck.PartialResults = append(subcheck.PartialResults, subcheck2) + subcheck2.AddPerfdata(&perf1) + subcheck2.AddPerfdata(&perf2) + subcheck.AddSubcheck(subcheck2) overall.AddSubcheck(subcheck) @@ -335,19 +312,16 @@ func TestOverall_withSubchecks_Perfdata(t *testing.T) { func TestOverall_withSubchecks_PartialResult(t *testing.T) { var overall Overall - subcheck3 := &PartialResult{ - Output: "SubSubSubcheck", - } + subcheck3 := NewPartialResult() + subcheck3.SetOutput("SubSubSubcheck") subcheck3.SetState(check.Critical) - subcheck2 := &PartialResult{ - Output: "SubSubcheck", - } + subcheck2 := NewPartialResult() + subcheck2.SetOutput("SubSubcheck") - subcheck := &PartialResult{ - Output: "PartialResult", - } + subcheck := NewPartialResult() + subcheck.SetOutput("PartialResult") perf1 := check.Perfdata{ Label: "foo", @@ -364,11 +338,11 @@ func TestOverall_withSubchecks_PartialResult(t *testing.T) { Uom: "B", } - subcheck3.Perfdata.Add(&perf3) - subcheck2.Perfdata.Add(&perf1) - subcheck2.Perfdata.Add(&perf2) - subcheck2.PartialResults = append(subcheck.PartialResults, subcheck3) - subcheck.PartialResults = append(subcheck.PartialResults, subcheck2) + subcheck3.AddPerfdata(&perf3) + subcheck2.AddPerfdata(&perf1) + subcheck2.AddPerfdata(&perf2) + subcheck2.AddSubcheck(subcheck3) + subcheck.AddSubcheck(subcheck2) overall.AddSubcheck(subcheck) @@ -391,21 +365,18 @@ func TestOverall_withSubchecks_PartialResult(t *testing.T) { func TestOverall_withSubchecks_PartialResultStatus(t *testing.T) { var overall Overall - subcheck := &PartialResult{ - Output: "Subcheck", - } + subcheck := NewPartialResult() + subcheck.SetOutput("Subcheck") subcheck.SetState(check.OK) - subsubcheck := &PartialResult{ - Output: "SubSubcheck", - } + subsubcheck := NewPartialResult() + subsubcheck.SetOutput("SubSubcheck") subsubcheck.SetState(check.Warning) - subsubsubcheck := &PartialResult{ - Output: "SubSubSubcheck", - } + subsubsubcheck := NewPartialResult() + subsubsubcheck.SetOutput("SubSubSubcheck") subsubsubcheck.SetState(check.Critical) @@ -431,31 +402,34 @@ func TestOverall_withSubchecks_PartialResultStatus(t *testing.T) { func TestSubchecksPerfdata(t *testing.T) { var overall Overall - check1 := &PartialResult{ - Output: "Check1", - Perfdata: check.PerfdataList{ - &check.Perfdata{ - Label: "foo", - Value: 23, - }, - &check.Perfdata{ - Label: "bar", - Value: 42, - }, + check1 := NewPartialResult() + check1.SetOutput("Check1") + + check1.AddPerfdata( + &check.Perfdata{ + Label: "foo", + Value: 23, }, - } + ) + + check1.AddPerfdata( + &check.Perfdata{ + Label: "bar", + Value: 42, + }, + ) check1.SetState(check.OK) - check2 := &PartialResult{ - Output: "Check2", - Perfdata: check.PerfdataList{ - &check.Perfdata{ - Label: "foo2 bar", - Value: 46, - }, + check2 := NewPartialResult() + check2.SetOutput("Check2") + + check2.AddPerfdata( + &check.Perfdata{ + Label: "foo2 bar", + Value: 46, }, - } + ) check2.SetState(check.Warning) @@ -601,7 +575,7 @@ func TestOverallGetOutput_WithMultipleStatesMultipleTimes(t *testing.T) { } func TestOverall_Add_WithRace(t *testing.T) { - o := &Overall{OKSummary: "unittest"} + o := &Overall{oKSummary: "unittest"} var wg sync.WaitGroup @@ -626,7 +600,7 @@ func TestOverall_AddSubcheck_WithRace(t *testing.T) { defer wg.Done() pr := NewPartialResult() pr.SetState(check.OK) - pr.Output = "goroutine" + pr.output = "goroutine" o.AddSubcheck(pr) }() } @@ -634,7 +608,7 @@ func TestOverall_AddSubcheck_WithRace(t *testing.T) { } func TestOverall_Get_WithRace(t *testing.T) { - o := &Overall{OKSummary: "unittest"} + o := &Overall{oKSummary: "unittest"} for range 3 { o.Add(check.OK, "OK") @@ -660,53 +634,3 @@ func TestOverall_Get_WithRace(t *testing.T) { wg.Wait() } - -func TestPartialResult_SetGet_WithRace(t *testing.T) { - pr := NewPartialResult() - - var wg sync.WaitGroup - - for range 3 { - wg.Add(2) - go func() { - defer wg.Done() - pr.SetState(check.Critical) - }() - go func() { - defer wg.Done() - _ = pr.GetStatus() - }() - } - wg.Wait() -} - -func TestPartialResult_AddSubcheck_WithRace(t *testing.T) { - parent := NewPartialResult() - parent.Output = "unittest" - - var wg sync.WaitGroup - for range 5 { - wg.Add(1) - go func() { - defer wg.Done() - child := NewPartialResult() - child.SetState(check.OK) - parent.AddSubcheck(child) - }() - } - wg.Wait() -} - -func TestPartialResult_SetDefaultState_WithRace(t *testing.T) { - pr := NewPartialResult() - - var wg sync.WaitGroup - for range 5 { - wg.Add(1) - go func() { - defer wg.Done() - pr.SetDefaultState(check.Warning) - }() - } - wg.Wait() -} diff --git a/result/partialResult.go b/result/partialResult.go new file mode 100644 index 0000000..e88d08a --- /dev/null +++ b/result/partialResult.go @@ -0,0 +1,168 @@ +package result + +import ( + "fmt" + "strings" + "sync" + + "github.com/NETWAYS/go-check" +) + +// PartialResult represents a sub-result for an Overall struct. +// Note that, a PartialResult must not be used on its own but always with an Overall. +type PartialResult struct { + perfdata check.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 + + mu sync.RWMutex +} + +// 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.mu.Lock() + defer s.mu.Unlock() + + s.partialResults = append(s.partialResults, subcheck) +} + +// AddPerfdata adds a Perfdata point to the PartialResult +func (s *PartialResult) AddPerfdata(perfdata *check.Perfdata) { + s.mu.Lock() + defer s.mu.Unlock() + + s.perfdata.Add(perfdata) +} + +// String returns the status and output of the PartialResult +func (s *PartialResult) String() string { + return fmt.Sprintf("[%s] %s", s.GetStatus(), strings.ReplaceAll(s.output, check.PerfdataSeparatorSymbol, " ")) +} + +// SetDefaultState sets a new default state for a PartialResult +func (s *PartialResult) SetDefaultState(state check.Status) { + s.mu.Lock() + defer s.mu.Unlock() + + s.defaultState = state + s.defaultStateSetExplicitly = true +} + +// SetState sets a state for a PartialResult +func (s *PartialResult) SetState(state check.Status) { + s.mu.Lock() + defer s.mu.Unlock() + + s.state = state + s.stateSetExplicitly = true +} + +// GetStatus returns the current state (ok, warning, critical, unknown) of the PartialResult +func (s *PartialResult) GetStatus() check.Status { + s.mu.RLock() + defer s.mu.RUnlock() + + if s.stateSetExplicitly { + return s.state + } + + if len(s.partialResults) == 0 { + if s.defaultStateSetExplicitly { + return s.defaultState + } + + return check.Unknown + } + + states := make([]check.Status, len(s.partialResults)) + + for i := range s.partialResults { + states[i] = s.partialResults[i].GetStatus() + } + + return check.WorstState(states...) +} + +// SetOutput sets the output of this PartialResult to the given string +func (s *PartialResult) SetOutput(output string) { + s.mu.Lock() + defer s.mu.Unlock() + + s.output = output +} + +// getPerfdata returns all subsequent perfdata as a concatenated string +func (s *PartialResult) getPerfdata() string { + var output strings.Builder + + if len(s.perfdata) > 0 { + output.WriteString(s.perfdata.String()) + } + + if s.partialResults != nil { + for _, ss := range s.partialResults { + output.WriteString(" " + ss.getPerfdata()) + } + } + + return strings.TrimSpace(output.String()) +} + +// getOutput generates indented output for all subsequent PartialResults +func (s *PartialResult) getOutput(indentLevel int) string { + var output strings.Builder + // The final result will look like this: + // [OK] Overall is OK + // \_ [OK] My PartialResult + output.WriteString(strings.Repeat(" ", indentLevel) + "\\_ " + s.String() + "\n") + + if s.partialResults != nil { + for _, ss := range s.partialResults { + output.WriteString(ss.getOutput(indentLevel + indentationOffset)) + } + } + + return output.String() +} + +func (s *PartialResult) getPartialResultFailedOutput() string { + if len(s.partialResults) == 0 { + // this is a leave node + return s.output + } + + result := "" + worstState := check.OK + + // Get the worst non-ok PartialResults output + for _, partRes := range s.partialResults { + if check.Compare(worstState, partRes.GetStatus()) > 0 { + result = partRes.getPartialResultFailedOutput() + worstState = partRes.GetStatus() + } + } + + return result +} diff --git a/result/partialResult_test.go b/result/partialResult_test.go new file mode 100644 index 0000000..c016eb5 --- /dev/null +++ b/result/partialResult_test.go @@ -0,0 +1,70 @@ +package result + +import ( + "sync" + "testing" + + "github.com/NETWAYS/go-check" +) + +func TestOverall_NewPartialResult(t *testing.T) { + actual := NewPartialResult() + + if actual.String() != "[UNKNOWN] " { + t.Fatalf("expected '[UNKNOWN] ', got %s", actual.String()) + } +} + +func TestPartialResult_SetGet_WithRace(t *testing.T) { + pr := NewPartialResult() + + var wg sync.WaitGroup + + for range 3 { + wg.Add(2) + go func() { + defer wg.Done() + pr.SetState(check.Critical) + }() + go func() { + defer wg.Done() + _ = pr.GetStatus() + }() + } + wg.Wait() +} + +func TestPartialResult_AddSubcheck_WithRace(t *testing.T) { + parent := NewPartialResult() + parent.SetOutput("unittest") + + var wg sync.WaitGroup + for range 5 { + wg.Add(1) + go func() { + defer wg.Done() + child := NewPartialResult() + child.SetState(check.OK) + parent.AddSubcheck(child) + }() + } + wg.Wait() +} + +func TestPartialResult_SetDefaultState_WithRace(t *testing.T) { + pr := NewPartialResult() + + var wg sync.WaitGroup + for range 5 { + wg.Add(1) + go func() { + defer wg.Done() + + example_perfdata := check.Perfdata{Label: "pd_test", Value: 5, Uom: "s"} + pr.AddPerfdata(&example_perfdata) + + pr.SetDefaultState(check.Warning) + }() + } + wg.Wait() +}