@@ -3,6 +3,7 @@ package receiver
33import (
44 "context"
55 "fmt"
6+ "regexp"
67 "sync"
78 "testing"
89 "time"
@@ -177,6 +178,8 @@ func TestPlainParseLine(t *testing.T) {
177178 {"metric.name;tag=value;k=v 42.15 1422642189\r \n " , "metric.name?k=v&tag=value" , 42.15 , 1422642189 },
178179 {"metric..name 42.15 -1\n " , "metric.name" , 42.15 , now },
179180 {"cpu.loadavg;env=test2;host=host1;env=test 21.4 1422642189\n " , "cpu.loadavg?env=test&host=host1" , 21.4 , 1422642189 },
181+ {"cpu.loadavg~ 21.4 1422642189\n " , "cpu.loadavg~" , 21.4 , 1422642189 },
182+ {"cpu.loadavg~;env=test2;host=host1;env=test 21.4 1422642189\n " , "cpu.loadavg~?env=test&host=host1" , 21.4 , 1422642189 },
180183 }
181184
182185 base := & Base {}
@@ -202,4 +205,128 @@ func TestPlainParseLine(t *testing.T) {
202205 }
203206 }
204207 }
208+
209+ tableWithValidation := [](struct {
210+ b string
211+ name string
212+ value float64
213+ timestamp uint32
214+ }){
215+ {b : "42" },
216+ {b : "" },
217+ {b : "\n " },
218+ {b : "metric..name 42 \n " },
219+ {b : "metric..name 42" },
220+ {b : "metric.name 42 a1422642189\n " },
221+ {b : "metric.name 42a 1422642189\n " },
222+ {b : "metric.name NaN 1422642189\n " },
223+ {b : "metric.name 42 NaN\n " },
224+ {"metric.name -42.76 1422642189\n " , "metric.name" , - 42.76 , 1422642189 },
225+ {"metric.name 42.15 1422642189\n " , "metric.name" , 42.15 , 1422642189 },
226+ {"metric..name 42.15 1422642189\n " , "metric.name" , 42.15 , 1422642189 },
227+ {"metric...name 42.15 1422642189\n " , "metric.name" , 42.15 , 1422642189 },
228+ {"metric.name 42.15 1422642189\r \n " , "metric.name" , 42.15 , 1422642189 },
229+ {"metric.name;tag=value;k=v 42.15 1422642189\r \n " , "metric.name?k=v&tag=value" , 42.15 , 1422642189 },
230+ {"metric..name 42.15 -1\n " , "metric.name" , 42.15 , now },
231+ {"cpu.loadavg;env=test2;host=host1;env=test 21.4 1422642189\n " , "cpu.loadavg?env=test&host=host1" , 21.4 , 1422642189 },
232+
233+ // Additional test cases for validation
234+ // Test invalid characters in metric names
235+ {b : "metric@name 42.15 1422642189\n " },
236+ {b : "metric#name 42.15 1422642189\n " },
237+ {b : "metric$name 42.15 1422642189\n " },
238+ {b : "metric%name 42.15 1422642189\n " },
239+ {b : "metric&name 42.15 1422642189\n " },
240+ {b : "metric*name 42.15 1422642189\n " },
241+ {b : "metric!name 42.15 1422642189\n " },
242+ {b : "metric name 42.15 1422642189\n " }, // space in metric name
243+ {b : "metric\t name 42.15 1422642189\n " }, // tab in metric name
244+ {b : "metric[name] 42.15 1422642189\n " },
245+ {b : "metric{name} 42.15 1422642189\n " },
246+ {b : "metric(name) 42.15 1422642189\n " },
247+ {b : "metric/name 42.15 1422642189\n " },
248+ {b : "metric\\ name 42.15 1422642189\n " },
249+ {b : "metric|name 42.15 1422642189\n " },
250+ {b : "metric?name 42.15 1422642189\n " },
251+ {b : "metric<name> 42.15 1422642189\n " },
252+ {b : "metric'name' 42.15 1422642189\n " },
253+ {b : "metric\" name\" 42.15 1422642189\n " },
254+
255+ // Test valid characters that should pass
256+ {"metric-name 42.15 1422642189\n " , "metric-name" , 42.15 , 1422642189 },
257+ {"metric_name 42.15 1422642189\n " , "metric_name" , 42.15 , 1422642189 },
258+ {"metric:name 42.15 1422642189\n " , "metric:name" , 42.15 , 1422642189 },
259+ {"metric.sub.name 42.15 1422642189\n " , "metric.sub.name" , 42.15 , 1422642189 },
260+ {"metric-123_test:data 42.15 1422642189\n " , "metric-123_test:data" , 42.15 , 1422642189 },
261+
262+ // Test invalid characters in tags
263+ {b : "metric.name;tag@=value 42.15 1422642189\n " },
264+ {b : "metric.name;tag=val@ue 42.15 1422642189\n " },
265+ {b : "metric.name;t ag=value 42.15 1422642189\n " },
266+ {b : "metric.name;tag=val ue 42.15 1422642189\n " },
267+ {b : "metric.name;tag#key=value 42.15 1422642189\n " },
268+ {b : "metric.name;tag=value! 42.15 1422642189\n " },
269+ {b : "metric.name;tag=value;key=val*ue 42.15 1422642189\n " },
270+ {b : "metric.name;tag=value;k ey=value 42.15 1422642189\n " },
271+ {b : "metric.name;tag=value;key=val\t ue 42.15 1422642189\n " },
272+ {b : "metric.name;tag=value;key=val\n ue 42.15 1422642189\n " },
273+
274+ // Test valid tags that should pass
275+ {"metric.name;env=prod 42.15 1422642189\n " , "metric.name?env=prod" , 42.15 , 1422642189 },
276+ {"metric.name;env=prod;region=us-east-1 42.15 1422642189\n " , "metric.name?env=prod®ion=us-east-1" , 42.15 , 1422642189 },
277+ {"metric.name;tag-name=tag-value 42.15 1422642189\n " , "metric.name?tag-name=tag-value" , 42.15 , 1422642189 },
278+ {"metric.name;tag_name=tag_value 42.15 1422642189\n " , "metric.name?tag_name=tag_value" , 42.15 , 1422642189 },
279+ {"metric.name;tag:name=tag:value 42.15 1422642189\n " , "metric.name?tag%3Aname=tag%3Avalue" , 42.15 , 1422642189 },
280+ {"metric.name;tag.name=tag.value 42.15 1422642189\n " , "metric.name?tag.name=tag.value" , 42.15 , 1422642189 },
281+
282+ // Test edge cases with multiple invalid characters
283+ {b : "metric@#$%name 42.15 1422642189\n " },
284+ {b : "metric.name;tag@#=value$% 42.15 1422642189\n " },
285+ {b : "met!ric.na@me;ta#g=val$ue 42.15 1422642189\n " },
286+
287+ // Test unicode characters (should fail validation)
288+ {b : "metric.名前 42.15 1422642189\n " },
289+ {b : "metric.name;tag=値 42.15 1422642189\n " },
290+ {b : "metric.name;标签=value 42.15 1422642189\n " },
291+ {b : "метрика.name 42.15 1422642189\n " },
292+
293+ // Test empty tag keys/values
294+ {b : "metric.name;=value 42.15 1422642189\n " },
295+ {b : "metric.name;= 42.15 1422642189\n " },
296+
297+ // Test metrics with numbers
298+ {"metric123 42.15 1422642189\n " , "metric123" , 42.15 , 1422642189 },
299+ {"123metric 42.15 1422642189\n " , "123metric" , 42.15 , 1422642189 },
300+ {"123 42.15 1422642189\n " , "123" , 42.15 , 1422642189 },
301+
302+ // Test metrics with only valid special characters
303+ {"metric-_.:name 42.15 1422642189\n " , "metric-_.:name" , 42.15 , 1422642189 },
304+ {"metric.name;tag-_.:key=tag-_.:value 42.15 1422642189\n " , "metric.name?tag-_.%3Akey=tag-_.%3Avalue" , 42.15 , 1422642189 },
305+
306+ // Additional tests for colon encoding
307+ {"host:port:metric 42.15 1422642189\n " , "host:port:metric" , 42.15 , 1422642189 },
308+ {"metric.name;service:port=web:8080 42.15 1422642189\n " , "metric.name?service%3Aport=web%3A8080" , 42.15 , 1422642189 },
309+ {"app:service:metric;env=prod:primary 42.15 1422642189\n " , "app:service:metric?env=prod%3Aprimary" , 42.15 , 1422642189 },
310+ }
311+
312+ baseWithValidation := & Base {blacklistRegex : regexp .MustCompile (`[^a-zA-Z0-9.;\-_:=]{1}` )}
313+ for _ , p := range tableWithValidation {
314+ name , value , timestamp , err := baseWithValidation .PlainParseLine ([]byte (p .b ), now , & tagBuf )
315+ if p .name == "" {
316+ // expected error
317+ if err == nil {
318+ t .Fatal ("error expected" )
319+ }
320+ } else {
321+ if string (name ) != p .name {
322+ t .Fatalf ("%#v != %#v" , string (name ), p .name )
323+ }
324+ if value != p .value {
325+ t .Fatalf ("%#v != %#v" , value , p .value )
326+ }
327+ if timestamp != p .timestamp {
328+ t .Fatalf ("%d != %d" , timestamp , p .timestamp )
329+ }
330+ }
331+ }
205332}
0 commit comments