github.com/influxdata/telegraf@v1.30.3/testutil/plugin_input/plugin.go (about)

     1  package input
     2  
     3  import (
     4  	_ "embed"
     5  	"errors"
     6  	"os"
     7  	"path/filepath"
     8  	"time"
     9  
    10  	"github.com/influxdata/telegraf"
    11  	"github.com/influxdata/telegraf/plugins/inputs"
    12  	"github.com/influxdata/telegraf/plugins/parsers/influx/influx_upstream"
    13  	"github.com/influxdata/telegraf/testutil"
    14  )
    15  
    16  //go:embed sample.conf
    17  var sampleConfig string
    18  
    19  // Example struct should be named the same as the Plugin
    20  type Plugin struct {
    21  	Files            []string               `toml:"files"`
    22  	DefaultTags      map[string]string      `toml:"default_tag_defs"`
    23  	AdditionalParams map[string]interface{} `toml:"additional_params"`
    24  	Parser           telegraf.Parser        `toml:"-"`
    25  	Log              telegraf.Logger        `toml:"-"`
    26  
    27  	// Settings used by test-code
    28  	Path             string `toml:"-"` // start path for relative files
    29  	ExpectedFilename string `toml:"-"` // filename of the expected metrics (default: expected.out)
    30  	UseTypeTag       string `toml:"-"` // if specified use this tag to infer metric type
    31  
    32  	// Test-data derived from the files
    33  	Expected              []telegraf.Metric `toml:"-"` // expected metrics
    34  	ExpectedErrors        []string          `toml:"-"` // expected errors
    35  	ShouldIgnoreTimestamp bool              `toml:"-"` // flag indicating if the expected metrics do have timestamps
    36  
    37  	// Internal data
    38  	inputFilenames []string
    39  }
    40  
    41  func (*Plugin) SampleConfig() string {
    42  	return sampleConfig
    43  }
    44  
    45  func (p *Plugin) Init() error {
    46  	// Setup the filenames
    47  	p.inputFilenames = make([]string, 0, len(p.Files))
    48  	for _, fn := range p.Files {
    49  		if !filepath.IsAbs(fn) && p.Path != "" {
    50  			fn = filepath.Join(p.Path, fn)
    51  		}
    52  		p.inputFilenames = append(p.inputFilenames, fn)
    53  	}
    54  
    55  	// Setup an influx parser for reading the expected metrics
    56  	expectedParser := &influx_upstream.Parser{}
    57  	if err := expectedParser.Init(); err != nil {
    58  		return err
    59  	}
    60  	expectedParser.SetTimeFunc(func() time.Time { return time.Time{} })
    61  
    62  	// Read the expected metrics if any
    63  	expectedFn := "expected.out"
    64  	if p.ExpectedFilename != "" {
    65  		expectedFn = p.ExpectedFilename
    66  	}
    67  	if !filepath.IsAbs(expectedFn) && p.Path != "" {
    68  		expectedFn = filepath.Join(p.Path, expectedFn)
    69  	}
    70  	if _, err := os.Stat(expectedFn); err == nil {
    71  		var err error
    72  		p.Expected, err = testutil.ParseMetricsFromFile(expectedFn, expectedParser)
    73  		if err != nil {
    74  			return err
    75  		}
    76  	}
    77  
    78  	// Read the expected errors if any
    79  	expectedErrorFn := "expected.err"
    80  	if !filepath.IsAbs(expectedErrorFn) && p.Path != "" {
    81  		expectedErrorFn = filepath.Join(p.Path, expectedErrorFn)
    82  	}
    83  	if _, err := os.Stat(expectedErrorFn); err == nil {
    84  		var err error
    85  		p.ExpectedErrors, err = testutil.ParseLinesFromFile(expectedErrorFn)
    86  		if err != nil {
    87  			return err
    88  		}
    89  		if len(p.ExpectedErrors) == 0 {
    90  			return errors.New("got empty expected errors file")
    91  		}
    92  	}
    93  
    94  	// Fixup the metric type if requested
    95  	if p.UseTypeTag != "" {
    96  		for i, m := range p.Expected {
    97  			typeTag, found := m.GetTag(p.UseTypeTag)
    98  			if !found {
    99  				continue
   100  			}
   101  			var mtype telegraf.ValueType
   102  			switch typeTag {
   103  			case "counter":
   104  				mtype = telegraf.Counter
   105  			case "gauge":
   106  				mtype = telegraf.Gauge
   107  			case "untyped":
   108  				mtype = telegraf.Untyped
   109  			case "summary":
   110  				mtype = telegraf.Summary
   111  			case "histogram":
   112  				mtype = telegraf.Histogram
   113  			default:
   114  				continue
   115  			}
   116  			m.SetType(mtype)
   117  			m.RemoveTag(p.UseTypeTag)
   118  			p.Expected[i] = m
   119  		}
   120  	}
   121  
   122  	// Determine if we should check the timestamps indicated by a missing
   123  	// timestamp in the expected input
   124  	for i, m := range p.Expected {
   125  		missingTimestamp := m.Time().IsZero()
   126  		if i == 0 {
   127  			p.ShouldIgnoreTimestamp = missingTimestamp
   128  			continue
   129  		}
   130  		if missingTimestamp != p.ShouldIgnoreTimestamp {
   131  			return errors.New("mixed timestamp and non-timestamp data in expected metrics")
   132  		}
   133  	}
   134  
   135  	// Set the parser's default tags, just in case
   136  	if p.Parser != nil {
   137  		p.Parser.SetDefaultTags(p.DefaultTags)
   138  	}
   139  
   140  	return nil
   141  }
   142  
   143  func (p *Plugin) Gather(acc telegraf.Accumulator) error {
   144  	if p.Parser == nil {
   145  		return errors.New("no parser defined")
   146  	}
   147  
   148  	for _, fn := range p.inputFilenames {
   149  		data, err := os.ReadFile(fn)
   150  		if err != nil {
   151  			return err
   152  		}
   153  		metrics, err := p.Parser.Parse(data)
   154  		if err != nil {
   155  			return err
   156  		}
   157  		for _, m := range metrics {
   158  			acc.AddMetric(m)
   159  		}
   160  	}
   161  
   162  	return nil
   163  }
   164  
   165  func (p *Plugin) SetParser(parser telegraf.Parser) {
   166  	p.Parser = parser
   167  	if len(p.DefaultTags) > 0 {
   168  		p.Parser.SetDefaultTags(p.DefaultTags)
   169  	}
   170  }
   171  
   172  // Register the plugin
   173  func init() {
   174  	inputs.Add("test", func() telegraf.Input {
   175  		return &Plugin{}
   176  	})
   177  }