refactor: make internals easier to test and add unit tests ()

This PR refactors most of the internals to make them easier to test (and also because the names didn't make sense). It adds unit tests for all internal components.

Reviewed-on: 
Co-authored-by: Emmanuel BENOÎT <tseeker@nocternity.net>
Co-committed-by: Emmanuel BENOÎT <tseeker@nocternity.net>
This commit is contained in:
Emmanuel BENOîT 2024-07-20 10:01:05 +02:00 committed by Emmanuel BENOîT
parent dcd732cc34
commit 78af496fe9
20 changed files with 939 additions and 369 deletions
pkg/plugin

View file

@ -1,122 +1,20 @@
// Package plugin implements a helper that can be used to implement a Nagios,
// Centreon, Icinga... service monitoring plugin.
package plugin // import nocternity.net/gomonop/pkg/perfdata
package plugin // import nocternity.net/gomonop/pkg/plugin
import (
"container/list"
"fmt"
"os"
"strings"
import "nocternity.net/gomonop/pkg/results"
"nocternity.net/gomonop/pkg/perfdata"
)
// Plugin represents the interface to a monitoring plugin.
type Plugin interface {
// Results accesses the results of the monitoring plugin.
Results() *results.Results
// Status represents the return status of the monitoring plugin. The
// corresponding integer value will be used as the program's exit code,
// to be interpreted by the monitoring system.
type Status int
// CheckArguments ensures that the arguments that were passed to the plugin
// actually make sense. Errors should be stored in the plugin's results.
CheckArguments() bool
// Plugin exit statuses.
const (
OK Status = iota
WARNING
CRITICAL
UNKNOWN
)
// String representations of the plugin statuses.
func (s Status) String() string {
return [...]string{"OK", "WARNING", "ERROR", "UNKNOWN"}[s]
// RunCheck actually runs whatever checks are implemented by the plugin and
// updates the results accordingly.
RunCheck()
}
// Plugin represents the monitoring plugin's state, including its name,
// return status and message, additional lines of text, and performance
// data to be encoded in the output.
type Plugin struct {
name string
status Status
message string
extraText *list.List
perfData map[string]*perfdata.PerfData
}
// New creates the plugin with `name` as its name and an unknown status.
func New(name string) *Plugin {
p := new(Plugin)
p.name = name
p.status = UNKNOWN
p.message = "no status set"
p.perfData = make(map[string]*perfdata.PerfData)
return p
}
// SetState sets the plugin's output code to `status` and its message to
// the specified `message`.
func (p *Plugin) SetState(status Status, message string) {
p.status = status
p.message = message
}
// AddLine adds the specified string to the extra output text buffer.
func (p *Plugin) AddLine(line string) {
if p.extraText == nil {
p.extraText = list.New()
}
p.extraText.PushBack(line)
}
// AddLinef formats the input and adds it to the text buffer.
func (p *Plugin) AddLinef(format string, data ...interface{}) {
p.AddLine(fmt.Sprintf(format, data...))
}
// AddLines add the specified `lines` to the output text.
func (p *Plugin) AddLines(lines []string) {
for _, line := range lines {
p.AddLine(line)
}
}
// AddPerfData adds performance data described by the "pd" argument to the
// output's performance data. If two performance data records are added for
// the same label, the program panics.
func (p *Plugin) AddPerfData(pd *perfdata.PerfData) {
_, exists := p.perfData[pd.Label]
if exists {
panic("duplicate performance data " + pd.Label)
}
p.perfData[pd.Label] = pd
}
// Done generates the plugin's text output from its name, status, text data
// and performance data, before exiting with the code corresponding to the
// status.
func (p *Plugin) Done() {
var strBuilder strings.Builder
strBuilder.WriteString(p.name)
strBuilder.WriteString(" ")
strBuilder.WriteString(p.status.String())
strBuilder.WriteString(": ")
strBuilder.WriteString(p.message)
if len(p.perfData) > 0 {
strBuilder.WriteString(" | ")
needSep := false
for _, data := range p.perfData {
if needSep {
strBuilder.WriteString(", ")
} else {
needSep = true
}
strBuilder.WriteString(data.String())
}
}
if p.extraText != nil {
for em := p.extraText.Front(); em != nil; em = em.Next() {
strBuilder.WriteString("\n")
//nolint:forcetypeassert // we want to panic if this isn't a string
strBuilder.WriteString(em.Value.(string))
}
}
fmt.Println(strBuilder.String())
os.Exit(int(p.status))
}
// Builder is a function that can be called in order to instantiate a plugin.
type Builder func() Plugin