github.com/grafana/pyroscope@v1.18.0/pkg/validation/limits_test.go (about)

     1  package validation
     2  
     3  import (
     4  	"encoding/json"
     5  	"reflect"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/grafana/dskit/flagext"
    10  	"github.com/prometheus/common/model"
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  	"gopkg.in/yaml.v3"
    14  )
    15  
    16  func TestLimitsTagsYamlMatchJson(t *testing.T) {
    17  	limits := reflect.TypeOf(Limits{})
    18  	n := limits.NumField()
    19  	var mismatch []string
    20  
    21  	for i := 0; i < n; i++ {
    22  		field := limits.Field(i)
    23  
    24  		// Note that we aren't requiring YAML and JSON tags to match, just that
    25  		// they either both exist or both don't exist.
    26  		hasYAMLTag := field.Tag.Get("yaml") != ""
    27  		hasJSONTag := field.Tag.Get("json") != ""
    28  
    29  		if hasYAMLTag != hasJSONTag {
    30  			mismatch = append(mismatch, field.Name)
    31  		}
    32  	}
    33  
    34  	assert.Empty(t, mismatch, "expected no mismatched JSON and YAML tags")
    35  }
    36  
    37  func TestLimitsYamlMatchJson(t *testing.T) {
    38  	inputYAML := `
    39  ingestion_rate_strategy: "some-strategy"
    40  ingestion_rate_mb: 34
    41  ingestion_burst_size_mb: 40
    42  max_label_name_length: 10
    43  max_label_value_length: 20
    44  max_label_names_per_series: 30
    45  reject_old_samples: true
    46  reject_old_samples_max_age: 40s
    47  creation_grace_period: 50s
    48  enforce_metric_name: true
    49  max_line_size: 60
    50  max_line_size_truncate: true
    51  max_streams_per_user: 70
    52  max_global_streams_per_user: 80
    53  max_chunks_per_query: 90
    54  max_query_series: 100
    55  max_query_lookback: 110s
    56  max_query_length: 120s
    57  max_query_parallelism: 130
    58  distributor_aggregation_window: 0s
    59  distributor_aggregation_duration: 0s
    60  cardinality_limit: 140
    61  max_streams_matchers_per_query: 150
    62  max_concurrent_tail_requests: 160
    63  max_entries_limit_per_query: 170
    64  max_cache_freshness_per_query: 180s
    65  split_queries_by_interval: 190s
    66  ruler_evaluation_delay_duration: 200s
    67  ruler_max_rules_per_rule_group: 210
    68  ruler_max_rule_groups_per_tenant: 220
    69  ruler_remote_write_sigv4_config:
    70    region: us-east-1
    71  per_tenant_override_config: ""
    72  per_tenant_override_period: 230s
    73  query_timeout: 5m
    74  shard_streams:
    75    enabled: true
    76    desired_rate: 4mb
    77    logging_enabled: true
    78  blocked_queries:
    79    - pattern: ".*foo.*"
    80      regex: true
    81  recording_rules:
    82    - metric_name: 'any-name'
    83      matchers: ['any-matcher']
    84      group_by: ['any-group-by']
    85      external_labels:
    86        - name: 'any-label-name'
    87          value: 'any-label-value'
    88  `
    89  	inputJSON := `
    90   {
    91    "ingestion_rate_strategy": "some-strategy",
    92    "ingestion_rate_mb": 34,
    93    "ingestion_burst_size_mb": 40,
    94    "max_label_name_length": 10,
    95    "max_label_value_length": 20,
    96    "max_label_names_per_series": 30,
    97    "reject_old_samples": true,
    98    "reject_old_samples_max_age": "40s",
    99    "creation_grace_period": "50s",
   100    "enforce_metric_name": true,
   101    "max_line_size": "60",
   102    "max_line_size_truncate": true,
   103    "max_streams_per_user": 70,
   104    "max_global_streams_per_user": 80,
   105    "max_chunks_per_query": 90,
   106    "max_query_series": 100,
   107    "max_query_lookback": "110s",
   108    "max_query_length": "120s",
   109    "max_query_parallelism": 130,
   110    "distributor_aggregation_window": "0s",
   111    "distributor_aggregation_duration": "0s",
   112    "cardinality_limit": 140,
   113    "max_streams_matchers_per_query": 150,
   114    "max_concurrent_tail_requests": 160,
   115    "max_entries_limit_per_query": 170,
   116    "max_cache_freshness_per_query": "180s",
   117    "split_queries_by_interval": "190s",
   118    "ruler_evaluation_delay_duration": "200s",
   119    "ruler_max_rules_per_rule_group": 210,
   120    "ruler_max_rule_groups_per_tenant":220,
   121    "ruler_remote_write_sigv4_config": {
   122      "region": "us-east-1"
   123    },
   124    "per_tenant_override_config": "",
   125    "per_tenant_override_period": "230s",
   126    "query_timeout": "5m",
   127    "shard_streams": {
   128      "desired_rate": "4mb",
   129      "enabled": true,
   130      "logging_enabled": true
   131    },
   132    "blocked_queries": [
   133    {
   134      "pattern": ".*foo.*",
   135      "regex": true
   136    }
   137    ],
   138    "recording_rules": [
   139    {
   140      "metric_name": "any-name",
   141      "matchers": ["any-matcher"],
   142      "group_by": ["any-group-by"],
   143      "external_labels": [
   144      {
   145        "name" : "any-label-name",
   146        "value" : "any-label-value"
   147      }
   148      ]
   149    }
   150    ]
   151   }
   152  `
   153  
   154  	limitsYAML := Limits{}
   155  	err := yaml.Unmarshal([]byte(inputYAML), &limitsYAML)
   156  	require.NoError(t, err, "expected to be able to unmarshal from YAML")
   157  
   158  	limitsJSON := Limits{}
   159  	err = json.Unmarshal([]byte(inputJSON), &limitsJSON)
   160  	require.NoError(t, err, "expected to be able to unmarshal from JSON")
   161  
   162  	assert.Equal(t, limitsYAML, limitsJSON)
   163  }
   164  
   165  func TestOverwriteMarshalingStringMapJSON(t *testing.T) {
   166  	m := NewOverwriteMarshalingStringMap(map[string]string{"foo": "bar"})
   167  
   168  	require.Nil(t, json.Unmarshal([]byte(`{"bazz": "buzz"}`), &m))
   169  	require.Equal(t, map[string]string{"bazz": "buzz"}, m.Map())
   170  	out, err := json.Marshal(m)
   171  	require.Nil(t, err)
   172  	var back OverwriteMarshalingStringMap
   173  	require.Nil(t, json.Unmarshal(out, &back))
   174  	require.Equal(t, m, back)
   175  }
   176  
   177  func TestOverwriteMarshalingStringMapYAML(t *testing.T) {
   178  	m := NewOverwriteMarshalingStringMap(map[string]string{"foo": "bar"})
   179  
   180  	require.Nil(t, yaml.Unmarshal([]byte(`{"bazz": "buzz"}`), &m))
   181  	require.Equal(t, map[string]string{"bazz": "buzz"}, m.Map())
   182  	out, err := yaml.Marshal(m)
   183  	require.Nil(t, err)
   184  	var back OverwriteMarshalingStringMap
   185  	require.Nil(t, yaml.Unmarshal(out, &back))
   186  	require.Equal(t, m, back)
   187  }
   188  
   189  func TestDistributorIngestionArtificialDelay(t *testing.T) {
   190  	tests := map[string]struct {
   191  		tenantID      string
   192  		defaultLimits func(*Limits)
   193  		tenantLimits  func(*Limits)
   194  		expectedDelay time.Duration
   195  	}{
   196  		"should not apply delay by default": {
   197  			tenantID:      "tenant-a",
   198  			tenantLimits:  func(*Limits) {},
   199  			expectedDelay: 0,
   200  		},
   201  		"should apply globally if set": {
   202  			tenantID: "tenant-a",
   203  			defaultLimits: func(l *Limits) {
   204  				l.IngestionArtificialDelay = model.Duration(time.Second)
   205  			},
   206  			tenantLimits:  func(*Limits) {},
   207  			expectedDelay: time.Second,
   208  		},
   209  		"should apply delay if a plain delay has been configured for the tenant": {
   210  			tenantID: "tenant-a",
   211  			tenantLimits: func(l *Limits) {
   212  				l.IngestionArtificialDelay = model.Duration(time.Second)
   213  			},
   214  			expectedDelay: time.Second,
   215  		},
   216  		"should tenant limit should override global": {
   217  			tenantID: "tenant-a",
   218  			defaultLimits: func(l *Limits) {
   219  				l.IngestionArtificialDelay = model.Duration(time.Second)
   220  			},
   221  			tenantLimits: func(l *Limits) {
   222  				l.IngestionArtificialDelay = model.Duration(0)
   223  			},
   224  			expectedDelay: 0,
   225  		},
   226  	}
   227  	for testName, testData := range tests {
   228  		t.Run(testName, func(t *testing.T) {
   229  			tenantLimits := &Limits{}
   230  			flagext.DefaultValues(tenantLimits)
   231  			if testData.defaultLimits != nil {
   232  				testData.defaultLimits(tenantLimits)
   233  			}
   234  			testData.tenantLimits(tenantLimits)
   235  
   236  			ov, err := NewOverrides(Limits{}, NewMockTenantLimits(map[string]*Limits{testData.tenantID: tenantLimits}))
   237  			require.NoError(t, err)
   238  			require.Equal(t, testData.expectedDelay, ov.IngestionArtificialDelay(testData.tenantID))
   239  		})
   240  	}
   241  }