...

Source file src/github.com/cybertec-postgresql/pgwatch/v5/internal/metrics/yaml_test.go

Documentation: github.com/cybertec-postgresql/pgwatch/v5/internal/metrics

     1  package metrics_test
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  	"testing"
     7  
     8  	"github.com/cybertec-postgresql/pgwatch/v5/internal/metrics"
     9  	"github.com/stretchr/testify/assert"
    10  	"gopkg.in/yaml.v3"
    11  )
    12  
    13  func TestDeaultMetrics(t *testing.T) {
    14  	fmr, err := metrics.NewYAMLMetricReaderWriter(ctx, "") // empty path is reserved for default metrics
    15  	assert.NoError(t, err)
    16  
    17  	// Test GetMetrics
    18  	metricsDefs, err := fmr.GetMetrics()
    19  	assert.NoError(t, err)
    20  
    21  	// Test WriteMetrics
    22  	err = fmr.WriteMetrics(metricsDefs)
    23  	assert.Error(t, err)
    24  
    25  	// Test DeleteMetric
    26  	err = fmr.DeleteMetric("test")
    27  	assert.Error(t, err)
    28  
    29  	// Test UpdateMetric
    30  	err = fmr.UpdateMetric("test", metrics.Metric{})
    31  	assert.Error(t, err)
    32  
    33  	// Test DeletePreset
    34  	err = fmr.DeletePreset("test")
    35  	assert.Error(t, err)
    36  
    37  	// Test UpdatePreset
    38  	err = fmr.UpdatePreset("test", metrics.Preset{})
    39  	assert.Error(t, err)
    40  }
    41  
    42  func TestWriteMetricsToFile(t *testing.T) {
    43  	// Define test data
    44  	metricDefs := metrics.Metrics{
    45  		MetricDefs: metrics.MetricDefs{
    46  			"test_metric": metrics.Metric{
    47  				SQLs: map[int]string{
    48  					1: "SELECT 1",
    49  				},
    50  				InitSQL:         "SELECT 1",
    51  				NodeStatus:      "primary",
    52  				Gauges:          []string{"gauge1", "gauge2"},
    53  				IsInstanceLevel: true,
    54  				StorageName:     "storage1",
    55  				Description:     "Test metric",
    56  			},
    57  		},
    58  		PresetDefs: metrics.PresetDefs{
    59  			"test_preset": metrics.Preset{
    60  				Description: "Test preset",
    61  				Metrics: map[string]float64{
    62  					"test_metric": 1.0,
    63  				},
    64  			},
    65  		},
    66  	}
    67  
    68  	// Create a temporary file for testing
    69  	tempDir := t.TempDir()
    70  	tempFile := filepath.Join(tempDir, "metrics.yaml")
    71  
    72  	fmr, err := metrics.NewYAMLMetricReaderWriter(ctx, tempFile)
    73  	assert.NoError(t, err)
    74  
    75  	// Call the function being tested
    76  	err = fmr.WriteMetrics(&metricDefs)
    77  	assert.NoError(t, err)
    78  
    79  	// Read the contents of the file
    80  	metrics, err := fmr.GetMetrics()
    81  	assert.NoError(t, err)
    82  
    83  	// Assert that the file contains the expected data
    84  	assert.Equal(t, metricDefs, *metrics)
    85  }
    86  func TestMetricsToFile(t *testing.T) {
    87  	// Define test data
    88  	metricDefs := metrics.Metrics{
    89  		MetricDefs: metrics.MetricDefs{
    90  			"existing_metric": metrics.Metric{
    91  				SQLs: map[int]string{
    92  					1: "SELECT 1",
    93  				},
    94  				InitSQL:         "SELECT 1",
    95  				NodeStatus:      "primary",
    96  				Gauges:          []string{"gauge1", "gauge2"},
    97  				IsInstanceLevel: true,
    98  				StorageName:     "storage1",
    99  				Description:     "Existing metric",
   100  			},
   101  		},
   102  		PresetDefs: metrics.PresetDefs{
   103  			"test_preset": metrics.Preset{
   104  				Description: "Test preset",
   105  				Metrics: map[string]float64{
   106  					"existing_metric": 1.0,
   107  				},
   108  			},
   109  		},
   110  	}
   111  
   112  	// Create a temporary file for testing
   113  	tempDir := t.TempDir()
   114  	tempFile := filepath.Join(tempDir, "metrics.yaml")
   115  
   116  	fmr, err := metrics.NewYAMLMetricReaderWriter(ctx, tempFile)
   117  	assert.NoError(t, err)
   118  
   119  	// Write initial metrics to the file
   120  	err = fmr.WriteMetrics(&metricDefs)
   121  	assert.NoError(t, err)
   122  
   123  	// Call the function being tested
   124  	newMetric := metrics.Metric{
   125  		SQLs: map[int]string{
   126  			1: "SELECT 2",
   127  		},
   128  		InitSQL:         "SELECT 2",
   129  		NodeStatus:      "primary",
   130  		Gauges:          []string{"gauge3", "gauge4"},
   131  		IsInstanceLevel: true,
   132  		StorageName:     "storage2",
   133  		Description:     "New metric",
   134  	}
   135  	err = fmr.UpdateMetric("new_metric", newMetric)
   136  	assert.NoError(t, err)
   137  
   138  	// Read the updated metrics from the file
   139  	updatedMetrics, err := fmr.GetMetrics()
   140  	assert.NoError(t, err)
   141  
   142  	// Assert that the metric was updated correctly
   143  	expectedMetrics := metricDefs
   144  	expectedMetrics.MetricDefs["new_metric"] = newMetric
   145  	assert.Equal(t, expectedMetrics, *updatedMetrics)
   146  
   147  	// Call the function being tested
   148  	err = fmr.DeleteMetric("new_metric")
   149  	assert.NoError(t, err)
   150  
   151  	// Read the updated metrics from the file
   152  	updatedMetrics, err = fmr.GetMetrics()
   153  	assert.NoError(t, err)
   154  
   155  	// Assert that the metric was deleted correctly
   156  	assert.Zero(t, updatedMetrics.MetricDefs["new_metric"])
   157  }
   158  
   159  func TestPresetsToFile(t *testing.T) {
   160  	// Define test data
   161  	presetDefs := metrics.PresetDefs{
   162  		"existing_preset": metrics.Preset{
   163  			Description: "Existing preset",
   164  			Metrics: map[string]float64{
   165  				"existing_metric": 1.0,
   166  			},
   167  		},
   168  	}
   169  
   170  	// Create a temporary file for testing
   171  	tempDir := t.TempDir()
   172  	tempFile := filepath.Join(tempDir, "metrics.yaml")
   173  
   174  	fmr, err := metrics.NewYAMLMetricReaderWriter(ctx, tempFile)
   175  	assert.NoError(t, err)
   176  
   177  	// Write initial presets to the file
   178  	err = fmr.WriteMetrics(&metrics.Metrics{
   179  		PresetDefs: presetDefs,
   180  	})
   181  	assert.NoError(t, err)
   182  
   183  	// Call the function being tested
   184  	newPreset := metrics.Preset{
   185  		Description: "New preset",
   186  		Metrics: map[string]float64{
   187  			"new_metric": 1.0,
   188  		},
   189  	}
   190  	err = fmr.UpdatePreset("new_preset", newPreset)
   191  	assert.NoError(t, err)
   192  
   193  	// Read the updated presets from the file
   194  	updatedMetrics, err := fmr.GetMetrics()
   195  	assert.NoError(t, err)
   196  
   197  	// Assert that the preset was updated correctly
   198  	expectedPresets := presetDefs
   199  	expectedPresets["new_preset"] = newPreset
   200  	assert.Equal(t, expectedPresets, updatedMetrics.PresetDefs)
   201  
   202  	// check the delete preset function
   203  	err = fmr.DeletePreset("new_preset")
   204  	assert.NoError(t, err)
   205  
   206  	// Read the updated presets from the file
   207  	updatedMetrics, err = fmr.GetMetrics()
   208  	assert.NoError(t, err)
   209  
   210  	// Assert that the preset was deleted correctly
   211  	assert.Zero(t, updatedMetrics.PresetDefs["new_preset"])
   212  }
   213  
   214  func TestErrorHandlingToFile(t *testing.T) {
   215  	fmr, err := metrics.NewYAMLMetricReaderWriter(ctx, "/") // empty path is reserved for default metrics
   216  	assert.NoError(t, err)
   217  
   218  	// Test WriteMetrics
   219  	err = fmr.WriteMetrics(&metrics.Metrics{})
   220  	assert.Error(t, err)
   221  
   222  	// Test GetMetrics
   223  	_, err = fmr.GetMetrics()
   224  	assert.Error(t, err)
   225  
   226  	// Test DeleteMetric
   227  	err = fmr.DeleteMetric("test")
   228  	assert.Error(t, err)
   229  
   230  	// Test UpdateMetric
   231  	err = fmr.UpdateMetric("test", metrics.Metric{})
   232  	assert.Error(t, err)
   233  
   234  	// Test DeletePreset
   235  	err = fmr.DeletePreset("test")
   236  	assert.Error(t, err)
   237  
   238  	// Test UpdatePreset
   239  	err = fmr.UpdatePreset("test", metrics.Preset{})
   240  	assert.Error(t, err)
   241  
   242  	// Test invalid YAML
   243  	tempDir := t.TempDir()
   244  	tempFile := filepath.Join(tempDir, "metrics.yaml")
   245  	file, err := os.Create(tempFile)
   246  	assert.NoError(t, err)
   247  	defer file.Close()
   248  	_, err = file.WriteString("invalid yaml")
   249  	assert.NoError(t, err)
   250  
   251  	fmr, err = metrics.NewYAMLMetricReaderWriter(ctx, tempFile)
   252  	assert.NoError(t, err)
   253  
   254  	_, err = fmr.GetMetrics()
   255  	assert.Error(t, err)
   256  }
   257  
   258  func TestCreateMetricAndPreset(t *testing.T) {
   259  
   260  	a := assert.New(t)
   261  
   262  	t.Run("YAML_CreateMetric_Success", func(t *testing.T) {
   263  		tmpFile := filepath.Join(t.TempDir(), "test_metrics.yaml")
   264  		defer os.Remove(tmpFile)
   265  
   266  		// Create YAML reader/writer
   267  		yamlrw, err := metrics.NewYAMLMetricReaderWriter(ctx, tmpFile)
   268  		a.NoError(err)
   269  
   270  		// Initialize empty metrics file first
   271  		emptyMetrics := &metrics.Metrics{
   272  			MetricDefs: make(map[string]metrics.Metric),
   273  			PresetDefs: make(map[string]metrics.Preset),
   274  		}
   275  		err = yamlrw.WriteMetrics(emptyMetrics)
   276  		a.NoError(err)
   277  
   278  		// Create a new metric
   279  		testMetric := metrics.Metric{
   280  			Description: "Test metric for creation",
   281  		}
   282  		err = yamlrw.CreateMetric("test_metric", testMetric)
   283  		a.NoError(err)
   284  
   285  		// Verify it was created
   286  		m, err := yamlrw.GetMetrics()
   287  		a.NoError(err)
   288  		a.Contains(m.MetricDefs, "test_metric")
   289  		a.Equal("Test metric for creation", m.MetricDefs["test_metric"].Description)
   290  
   291  		// Try to create the same metric again - should fail
   292  		err = yamlrw.CreateMetric("test_metric", testMetric)
   293  		a.Error(err)
   294  		a.Equal(metrics.ErrMetricExists, err)
   295  	})
   296  
   297  	t.Run("YAML_CreatePreset_Success", func(t *testing.T) {
   298  		tmpFile := filepath.Join(t.TempDir(), "test_presets.yaml")
   299  		defer os.Remove(tmpFile)
   300  
   301  		yamlrw, err := metrics.NewYAMLMetricReaderWriter(ctx, tmpFile)
   302  		a.NoError(err)
   303  
   304  		// Initialize empty metrics file first
   305  		emptyMetrics := &metrics.Metrics{
   306  			MetricDefs: make(map[string]metrics.Metric),
   307  			PresetDefs: make(map[string]metrics.Preset),
   308  		}
   309  		err = yamlrw.WriteMetrics(emptyMetrics)
   310  		a.NoError(err)
   311  
   312  		// Create a new preset
   313  		testPreset := metrics.Preset{
   314  			Description: "Test preset for creation",
   315  			Metrics:     map[string]float64{"db_stats": 60},
   316  		}
   317  		err = yamlrw.CreatePreset("test_preset", testPreset)
   318  		a.NoError(err)
   319  
   320  		// Verify it was created
   321  		m, err := yamlrw.GetMetrics()
   322  		a.NoError(err)
   323  		a.Contains(m.PresetDefs, "test_preset")
   324  		a.Equal("Test preset for creation", m.PresetDefs["test_preset"].Description)
   325  
   326  		// Try to create the same preset again - should fail
   327  		err = yamlrw.CreatePreset("test_preset", testPreset)
   328  		a.Error(err)
   329  		a.Equal(metrics.ErrPresetExists, err)
   330  	})
   331  }
   332  
   333  func TestMetricsDir(t *testing.T) {
   334  	a := assert.New(t)
   335  
   336  	// first metrics file data
   337  	metrics1 := metrics.Metrics{
   338  		MetricDefs: map[string]metrics.Metric{
   339  			"metric1": {
   340  				Description: "metric1 description",
   341  			},
   342  		},
   343  		PresetDefs: map[string]metrics.Preset{
   344  			"preset1": {
   345  				Description: "preset1 description",
   346  				Metrics: map[string]float64{
   347  					"metric1": 10,
   348  				},
   349  			},
   350  		},
   351  	}
   352  
   353  	// second metrics file data
   354  	metrics2 := metrics.Metrics{
   355  		MetricDefs: map[string]metrics.Metric{
   356  			"metric2": {
   357  				Description: "metric2 description",
   358  			},
   359  		},
   360  		PresetDefs: map[string]metrics.Preset{
   361  			"preset2": {
   362  				Description: "preset2 description",
   363  				Metrics: map[string]float64{
   364  					"metric2": 10,
   365  				},
   366  			},
   367  		},
   368  	}
   369  
   370  	metrics1File, err := yaml.Marshal(metrics1)
   371  	a.NoError(err)
   372  	metrics2File, err := yaml.Marshal(metrics2)
   373  	a.NoError(err)
   374  
   375  	// write data to different files in a folder
   376  	tempDir := t.TempDir()
   377  	err = os.WriteFile(filepath.Join(tempDir, "metrics1.yaml"), metrics1File, 0644)
   378  	a.NoError(err)
   379  	err = os.WriteFile(filepath.Join(tempDir, "metrics2.yaml"), metrics2File, 0644)
   380  	a.NoError(err)
   381  
   382  	// use folder of yaml files for metrics configs
   383  	yamlrw, err := metrics.NewYAMLMetricReaderWriter(ctx, tempDir)
   384  	a.NoError(err)
   385  
   386  	// load metrics configs from folder
   387  	ms, err := yamlrw.GetMetrics()
   388  	a.NoError(err)
   389  	a.Equal("metric1 description", ms.MetricDefs["metric1"].Description)
   390  	a.Equal("preset1 description", ms.PresetDefs["preset1"].Description)
   391  	a.Equal("metric2 description", ms.MetricDefs["metric2"].Description)
   392  	a.Equal("preset2 description", ms.PresetDefs["preset2"].Description)
   393  }