github.com/ari-anchor/sei-tendermint@v0.0.0-20230519144642-dc826b7b56bb/scripts/metricsgen/metricsgen_test.go (about)

     1  package main_test
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"go/parser"
     7  	"go/token"
     8  	"io"
     9  	"io/ioutil"
    10  	"os"
    11  	"path"
    12  	"path/filepath"
    13  	"testing"
    14  
    15  	metricsgen "github.com/ari-anchor/sei-tendermint/scripts/metricsgen"
    16  	"github.com/stretchr/testify/require"
    17  )
    18  
    19  const testDataDir = "./testdata"
    20  
    21  func TestSimpleTemplate(t *testing.T) {
    22  	m := metricsgen.ParsedMetricField{
    23  		TypeName:    "Histogram",
    24  		FieldName:   "MyMetric",
    25  		MetricName:  "request_count",
    26  		Description: "how many requests were made since the start of the process",
    27  		Labels:      "first, second, third",
    28  	}
    29  	td := metricsgen.TemplateData{
    30  		Package:       "mypack",
    31  		ParsedMetrics: []metricsgen.ParsedMetricField{m},
    32  	}
    33  	b := bytes.NewBuffer([]byte{})
    34  	err := metricsgen.GenerateMetricsFile(b, td)
    35  	if err != nil {
    36  		t.Fatalf("unable to parse template %v", err)
    37  	}
    38  }
    39  
    40  func TestFromData(t *testing.T) {
    41  	infos, err := ioutil.ReadDir(testDataDir)
    42  	if err != nil {
    43  		t.Fatalf("unable to open file %v", err)
    44  	}
    45  	for _, dir := range infos {
    46  		t.Run(dir.Name(), func(t *testing.T) {
    47  			if !dir.IsDir() {
    48  				t.Fatalf("expected file %s to be directory", dir.Name())
    49  			}
    50  			dirName := path.Join(testDataDir, dir.Name())
    51  			pt, err := metricsgen.ParseMetricsDir(dirName, "Metrics")
    52  			if err != nil {
    53  				t.Fatalf("unable to parse from dir %q: %v", dir, err)
    54  			}
    55  			outFile := path.Join(dirName, "out.go")
    56  			if err != nil {
    57  				t.Fatalf("unable to open file %s: %v", outFile, err)
    58  			}
    59  			of, err := os.Create(outFile)
    60  			if err != nil {
    61  				t.Fatalf("unable to open file %s: %v", outFile, err)
    62  			}
    63  			defer os.Remove(outFile)
    64  			if err := metricsgen.GenerateMetricsFile(of, pt); err != nil {
    65  				t.Fatalf("unable to generate metrics file %s: %v", outFile, err)
    66  			}
    67  			if _, err := parser.ParseFile(token.NewFileSet(), outFile, nil, parser.AllErrors); err != nil {
    68  				t.Fatalf("unable to parse generated file %s: %v", outFile, err)
    69  			}
    70  			bNew, err := ioutil.ReadFile(outFile)
    71  			if err != nil {
    72  				t.Fatalf("unable to read generated file %s: %v", outFile, err)
    73  			}
    74  			goldenFile := path.Join(dirName, "metrics.gen.go")
    75  			bOld, err := ioutil.ReadFile(goldenFile)
    76  			if err != nil {
    77  				t.Fatalf("unable to read file %s: %v", goldenFile, err)
    78  			}
    79  			if !bytes.Equal(bNew, bOld) {
    80  				t.Fatalf("newly generated code in file %s does not match golden file %s\n"+
    81  					"if the output of the metricsgen tool is expected to change run the following make target: \n"+
    82  					"\tmake metrics", outFile, goldenFile)
    83  			}
    84  		})
    85  	}
    86  }
    87  
    88  func TestParseMetricsStruct(t *testing.T) {
    89  	const pkgName = "mypkg"
    90  	metricsTests := []struct {
    91  		name          string
    92  		shouldError   bool
    93  		metricsStruct string
    94  		expected      metricsgen.TemplateData
    95  	}{
    96  		{
    97  			name: "basic",
    98  			metricsStruct: `type Metrics struct {
    99  				myGauge metrics.Gauge
   100  			}`,
   101  			expected: metricsgen.TemplateData{
   102  				Package: pkgName,
   103  				ParsedMetrics: []metricsgen.ParsedMetricField{
   104  					{
   105  						TypeName:   "Gauge",
   106  						FieldName:  "myGauge",
   107  						MetricName: "my_gauge",
   108  					},
   109  				},
   110  			},
   111  		},
   112  		{
   113  			name: "histogram",
   114  			metricsStruct: "type Metrics struct {\n" +
   115  				"myHistogram metrics.Histogram `metrics_buckettype:\"exp\" metrics_bucketsizes:\"1, 100, .8\"`\n" +
   116  				"}",
   117  			expected: metricsgen.TemplateData{
   118  				Package: pkgName,
   119  				ParsedMetrics: []metricsgen.ParsedMetricField{
   120  					{
   121  						TypeName:   "Histogram",
   122  						FieldName:  "myHistogram",
   123  						MetricName: "my_histogram",
   124  
   125  						HistogramOptions: metricsgen.HistogramOpts{
   126  							BucketType:  "stdprometheus.ExponentialBuckets",
   127  							BucketSizes: "1, 100, .8",
   128  						},
   129  					},
   130  				},
   131  			},
   132  		},
   133  		{
   134  			name: "labeled name",
   135  			metricsStruct: "type Metrics struct {\n" +
   136  				"myCounter metrics.Counter `metrics_name:\"new_name\"`\n" +
   137  				"}",
   138  			expected: metricsgen.TemplateData{
   139  				Package: pkgName,
   140  				ParsedMetrics: []metricsgen.ParsedMetricField{
   141  					{
   142  						TypeName:   "Counter",
   143  						FieldName:  "myCounter",
   144  						MetricName: "new_name",
   145  					},
   146  				},
   147  			},
   148  		},
   149  		{
   150  			name: "metric labels",
   151  			metricsStruct: "type Metrics struct {\n" +
   152  				"myCounter metrics.Counter `metrics_labels:\"label1,label2\"`\n" +
   153  				"}",
   154  			expected: metricsgen.TemplateData{
   155  				Package: pkgName,
   156  				ParsedMetrics: []metricsgen.ParsedMetricField{
   157  					{
   158  						TypeName:   "Counter",
   159  						FieldName:  "myCounter",
   160  						MetricName: "my_counter",
   161  						Labels:     "\"label1\",\"label2\"",
   162  					},
   163  				},
   164  			},
   165  		},
   166  		{
   167  			name: "ignore non-metric field",
   168  			metricsStruct: `type Metrics struct {
   169  				myCounter metrics.Counter
   170  				nonMetric string
   171  				}`,
   172  			expected: metricsgen.TemplateData{
   173  				Package: pkgName,
   174  				ParsedMetrics: []metricsgen.ParsedMetricField{
   175  					{
   176  						TypeName:   "Counter",
   177  						FieldName:  "myCounter",
   178  						MetricName: "my_counter",
   179  					},
   180  				},
   181  			},
   182  		},
   183  	}
   184  	for _, testCase := range metricsTests {
   185  		t.Run(testCase.name, func(t *testing.T) {
   186  			dir, err := os.MkdirTemp(os.TempDir(), "metricsdir")
   187  			if err != nil {
   188  				t.Fatalf("unable to create directory: %v", err)
   189  			}
   190  			defer os.Remove(dir)
   191  			f, err := os.Create(filepath.Join(dir, "metrics.go"))
   192  			if err != nil {
   193  				t.Fatalf("unable to open file: %v", err)
   194  			}
   195  			pkgLine := fmt.Sprintf("package %s\n", pkgName)
   196  			importClause := `
   197  			import(
   198  				"github.com/go-kit/kit/metrics"
   199  			)
   200  			`
   201  
   202  			_, err = io.WriteString(f, pkgLine)
   203  			require.NoError(t, err)
   204  			_, err = io.WriteString(f, importClause)
   205  			require.NoError(t, err)
   206  			_, err = io.WriteString(f, testCase.metricsStruct)
   207  			require.NoError(t, err)
   208  
   209  			td, err := metricsgen.ParseMetricsDir(dir, "Metrics")
   210  			if testCase.shouldError {
   211  				require.Error(t, err)
   212  			} else {
   213  				require.NoError(t, err)
   214  				require.Equal(t, testCase.expected, td)
   215  			}
   216  		})
   217  	}
   218  }
   219  
   220  func TestParseAliasedMetric(t *testing.T) {
   221  	aliasedData := `
   222  			package mypkg
   223  
   224  			import(
   225  				mymetrics "github.com/go-kit/kit/metrics"
   226  			)
   227  			type Metrics struct {
   228  				m mymetrics.Gauge
   229  			}
   230  			`
   231  	dir, err := os.MkdirTemp(os.TempDir(), "metricsdir")
   232  	if err != nil {
   233  		t.Fatalf("unable to create directory: %v", err)
   234  	}
   235  	defer os.Remove(dir)
   236  	f, err := os.Create(filepath.Join(dir, "metrics.go"))
   237  	if err != nil {
   238  		t.Fatalf("unable to open file: %v", err)
   239  	}
   240  	_, err = io.WriteString(f, aliasedData)
   241  	if err != nil {
   242  		t.Fatalf("unable to write to file: %v", err)
   243  	}
   244  	td, err := metricsgen.ParseMetricsDir(dir, "Metrics")
   245  	require.NoError(t, err)
   246  
   247  	expected :=
   248  		metricsgen.TemplateData{
   249  			Package: "mypkg",
   250  			ParsedMetrics: []metricsgen.ParsedMetricField{
   251  				{
   252  					TypeName:   "Gauge",
   253  					FieldName:  "m",
   254  					MetricName: "m",
   255  				},
   256  			},
   257  		}
   258  	require.Equal(t, expected, td)
   259  }