1// Copyright 2017 The Prometheus Authors 2// Licensed under the Apache License, Version 2.0 (the "License"); 3// you may not use this file except in compliance with the License. 4// You may obtain a copy of the License at 5// 6// http://www.apache.org/licenses/LICENSE-2.0 7// 8// Unless required by applicable law or agreed to in writing, software 9// distributed under the License is distributed on an "AS IS" BASIS, 10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11// See the License for the specific language governing permissions and 12// limitations under the License. 13 14package remote 15 16import ( 17 "reflect" 18 "sort" 19 "testing" 20 21 "github.com/prometheus/common/model" 22 "github.com/prometheus/prometheus/storage/metric" 23) 24 25func TestValidateLabelsAndMetricName(t *testing.T) { 26 tests := []struct { 27 result model.Matrix 28 expectedErr string 29 shouldPass bool 30 }{ 31 { 32 result: model.Matrix{ 33 &model.SampleStream{ 34 Metric: model.Metric{ 35 "__name__": "name", 36 "labelName": "labelValue", 37 }, 38 }, 39 }, 40 expectedErr: "", 41 shouldPass: true, 42 }, 43 { 44 result: model.Matrix{ 45 &model.SampleStream{ 46 Metric: model.Metric{ 47 "__name__": "name", 48 "_labelName": "labelValue", 49 }, 50 }, 51 }, 52 expectedErr: "", 53 shouldPass: true, 54 }, 55 { 56 result: model.Matrix{ 57 &model.SampleStream{ 58 Metric: model.Metric{ 59 "__name__": "name", 60 "@labelName": "labelValue", 61 }, 62 }, 63 }, 64 expectedErr: "Invalid label name: @labelName", 65 shouldPass: false, 66 }, 67 { 68 result: model.Matrix{ 69 &model.SampleStream{ 70 Metric: model.Metric{ 71 "__name__": "name", 72 "123labelName": "labelValue", 73 }, 74 }, 75 }, 76 expectedErr: "Invalid label name: 123labelName", 77 shouldPass: false, 78 }, 79 { 80 result: model.Matrix{ 81 &model.SampleStream{ 82 Metric: model.Metric{ 83 "__name__": "name", 84 "": "labelValue", 85 }, 86 }, 87 }, 88 expectedErr: "Invalid label name: ", 89 shouldPass: false, 90 }, 91 { 92 result: model.Matrix{ 93 &model.SampleStream{ 94 Metric: model.Metric{ 95 "__name__": "name", 96 "labelName": model.LabelValue([]byte{0xff}), 97 }, 98 }, 99 }, 100 expectedErr: "Invalid label value: " + string([]byte{0xff}), 101 shouldPass: false, 102 }, 103 { 104 result: model.Matrix{ 105 &model.SampleStream{ 106 Metric: model.Metric{ 107 "__name__": "@invalid_name", 108 }, 109 }, 110 }, 111 expectedErr: "Invalid metric name: @invalid_name", 112 shouldPass: false, 113 }, 114 } 115 116 for _, test := range tests { 117 err := validateLabelsAndMetricName(test.result) 118 if test.shouldPass { 119 if err != nil { 120 t.Fatalf("Test should pass, got unexpected error: %v", err) 121 } 122 continue 123 } 124 if err != nil { 125 if err.Error() != test.expectedErr { 126 t.Fatalf("Unexpected error, got: %v, expected: %v", err, test.expectedErr) 127 } 128 } else { 129 t.Fatalf("Expected error, got none") 130 } 131 } 132} 133 134func mustNewLabelMatcher(mt metric.MatchType, name model.LabelName, val model.LabelValue) *metric.LabelMatcher { 135 m, err := metric.NewLabelMatcher(mt, name, val) 136 if err != nil { 137 panic(err) 138 } 139 return m 140} 141 142func TestAddExternalLabels(t *testing.T) { 143 tests := []struct { 144 el model.LabelSet 145 inMatchers metric.LabelMatchers 146 outMatchers metric.LabelMatchers 147 added model.LabelSet 148 }{ 149 { 150 el: model.LabelSet{}, 151 inMatchers: metric.LabelMatchers{ 152 mustNewLabelMatcher(metric.Equal, "job", "api-server"), 153 }, 154 outMatchers: metric.LabelMatchers{ 155 mustNewLabelMatcher(metric.Equal, "job", "api-server"), 156 }, 157 added: model.LabelSet{}, 158 }, 159 { 160 el: model.LabelSet{"region": "europe", "dc": "berlin-01"}, 161 inMatchers: metric.LabelMatchers{ 162 mustNewLabelMatcher(metric.Equal, "job", "api-server"), 163 }, 164 outMatchers: metric.LabelMatchers{ 165 mustNewLabelMatcher(metric.Equal, "job", "api-server"), 166 mustNewLabelMatcher(metric.Equal, "region", "europe"), 167 mustNewLabelMatcher(metric.Equal, "dc", "berlin-01"), 168 }, 169 added: model.LabelSet{"region": "europe", "dc": "berlin-01"}, 170 }, 171 { 172 el: model.LabelSet{"region": "europe", "dc": "berlin-01"}, 173 inMatchers: metric.LabelMatchers{ 174 mustNewLabelMatcher(metric.Equal, "job", "api-server"), 175 mustNewLabelMatcher(metric.Equal, "dc", "munich-02"), 176 }, 177 outMatchers: metric.LabelMatchers{ 178 mustNewLabelMatcher(metric.Equal, "job", "api-server"), 179 mustNewLabelMatcher(metric.Equal, "region", "europe"), 180 mustNewLabelMatcher(metric.Equal, "dc", "munich-02"), 181 }, 182 added: model.LabelSet{"region": "europe"}, 183 }, 184 } 185 186 for i, test := range tests { 187 q := querier{ 188 externalLabels: test.el, 189 } 190 191 matchers, added := q.addExternalLabels(test.inMatchers) 192 193 sort.Slice(test.outMatchers, func(i, j int) bool { return test.outMatchers[i].Name < test.outMatchers[j].Name }) 194 sort.Slice(matchers, func(i, j int) bool { return matchers[i].Name < matchers[j].Name }) 195 196 if !reflect.DeepEqual(matchers, test.outMatchers) { 197 t.Fatalf("%d. unexpected matchers; want %v, got %v", i, test.outMatchers, matchers) 198 } 199 if !reflect.DeepEqual(added, test.added) { 200 t.Fatalf("%d. unexpected added labels; want %v, got %v", i, test.added, added) 201 } 202 } 203} 204