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 }