point_test.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. // Copyright 2020-2021 InfluxData, Inc. All rights reserved.
  2. // Use of this source code is governed by MIT
  3. // license that can be found in the LICENSE file.
  4. package write
  5. import (
  6. "bytes"
  7. "fmt"
  8. "math"
  9. "math/rand"
  10. "reflect"
  11. "strings"
  12. "testing"
  13. "time"
  14. lp "github.com/influxdata/line-protocol"
  15. "github.com/stretchr/testify/assert"
  16. "github.com/stretchr/testify/require"
  17. )
  18. var points []*Point
  19. func init() {
  20. points = make([]*Point, 5000)
  21. rand.Seed(321)
  22. t := time.Now()
  23. for i := 0; i < len(points); i++ {
  24. points[i] = NewPoint(
  25. "test",
  26. map[string]string{
  27. "id": fmt.Sprintf("rack_%v", i%100),
  28. "vendor": "AWS",
  29. "hostname": fmt.Sprintf("host_%v", i%10),
  30. },
  31. map[string]interface{}{
  32. "temperature": rand.Float64() * 80.0,
  33. "disk_free": rand.Float64() * 1000.0,
  34. "disk_total": (i/10 + 1) * 1000000,
  35. "mem_total": (i/100 + 1) * 10000000,
  36. "mem_free": rand.Float64() * 10000000.0,
  37. },
  38. t)
  39. if i%10 == 0 {
  40. t = t.Add(time.Second)
  41. }
  42. }
  43. }
  44. type ia int
  45. type st struct {
  46. d float64
  47. b bool
  48. }
  49. func (s st) String() string {
  50. return fmt.Sprintf("%.2f d %v", s.d, s.b)
  51. }
  52. func TestConvert(t *testing.T) {
  53. obj := []struct {
  54. val interface{}
  55. targetVal interface{}
  56. }{
  57. {int(-5), int64(-5)},
  58. {int8(5), int64(5)},
  59. {int16(-51), int64(-51)},
  60. {int32(5), int64(5)},
  61. {int64(555), int64(555)},
  62. {uint(5), uint64(5)},
  63. {uint8(55), uint64(55)},
  64. {uint16(51), uint64(51)},
  65. {uint32(555), uint64(555)},
  66. {uint64(5555), uint64(5555)},
  67. {"a", "a"},
  68. {true, true},
  69. {float32(1.2), float64(1.2)},
  70. {float64(2.2), float64(2.2)},
  71. {ia(4), "4"},
  72. {[]string{"a", "b"}, "[a b]"},
  73. {map[int]string{1: "a", 2: "b"}, "map[1:a 2:b]"},
  74. {struct {
  75. a int
  76. s string
  77. }{0, "x"}, "{0 x}"},
  78. {st{1.22, true}, "1.22 d true"},
  79. }
  80. for _, tv := range obj {
  81. t.Run(reflect.TypeOf(tv.val).String(), func(t *testing.T) {
  82. v := convertField(tv.val)
  83. assert.Equal(t, reflect.TypeOf(tv.targetVal), reflect.TypeOf(v))
  84. if f, ok := tv.targetVal.(float64); ok {
  85. val := reflect.ValueOf(tv.val)
  86. ft := reflect.TypeOf(float64(0))
  87. assert.True(t, val.Type().ConvertibleTo(ft))
  88. valf := val.Convert(ft)
  89. assert.True(t, math.Abs(f-valf.Float()) < 1e-6)
  90. } else {
  91. assert.EqualValues(t, tv.targetVal, v)
  92. }
  93. })
  94. }
  95. }
  96. func TestNewPoint(t *testing.T) {
  97. p := NewPoint(
  98. "test",
  99. map[string]string{
  100. "id": "10ad=",
  101. "ven=dor": "AWS",
  102. `host"name`: `ho\st "a"`,
  103. `x\" x`: "a b",
  104. },
  105. map[string]interface{}{
  106. "float64": 80.1234567,
  107. "float32": float32(80.0),
  108. "int": -1234567890,
  109. "int8": int8(-34),
  110. "int16": int16(-3456),
  111. "int32": int32(-34567),
  112. "int64": int64(-1234567890),
  113. "uint": uint(12345677890),
  114. "uint8": uint8(34),
  115. "uint16": uint16(3456),
  116. "uint32": uint32(34578),
  117. "uint 64": uint64(41234567890),
  118. "bo\\ol": false,
  119. `"string"`: `six, "seven", eight`,
  120. "stri=ng": `six=seven\, eight`,
  121. "time": time.Date(2020, time.March, 20, 10, 30, 23, 123456789, time.UTC),
  122. "duration": 4*time.Hour + 24*time.Minute + 3*time.Second,
  123. },
  124. time.Unix(60, 70))
  125. verifyPoint(t, p)
  126. }
  127. func verifyPoint(t *testing.T, p *Point) {
  128. assert.Equal(t, p.Name(), "test")
  129. require.Len(t, p.TagList(), 4)
  130. assert.Equal(t, p.TagList(), []*lp.Tag{
  131. {Key: `host"name`, Value: "ho\\st \"a\""},
  132. {Key: "id", Value: "10ad="},
  133. {Key: `ven=dor`, Value: "AWS"},
  134. {Key: "x\\\" x", Value: "a b"}})
  135. require.Len(t, p.FieldList(), 17)
  136. assert.Equal(t, p.FieldList(), []*lp.Field{
  137. {Key: `"string"`, Value: `six, "seven", eight`},
  138. {Key: "bo\\ol", Value: false},
  139. {Key: "duration", Value: "4h24m3s"},
  140. {Key: "float32", Value: 80.0},
  141. {Key: "float64", Value: 80.1234567},
  142. {Key: "int", Value: int64(-1234567890)},
  143. {Key: "int16", Value: int64(-3456)},
  144. {Key: "int32", Value: int64(-34567)},
  145. {Key: "int64", Value: int64(-1234567890)},
  146. {Key: "int8", Value: int64(-34)},
  147. {Key: "stri=ng", Value: `six=seven\, eight`},
  148. {Key: "time", Value: "2020-03-20T10:30:23.123456789Z"},
  149. {Key: "uint", Value: uint64(12345677890)},
  150. {Key: "uint 64", Value: uint64(41234567890)},
  151. {Key: "uint16", Value: uint64(3456)},
  152. {Key: "uint32", Value: uint64(34578)},
  153. {Key: "uint8", Value: uint64(34)},
  154. })
  155. line := PointToLineProtocol(p, time.Nanosecond)
  156. assert.True(t, strings.HasSuffix(line, "\n"))
  157. //cut off last \n char
  158. line = line[:len(line)-1]
  159. assert.Equal(t, line, `test,host"name=ho\st\ "a",id=10ad\=,ven\=dor=AWS,x\"\ x=a\ b "string"="six, \"seven\", eight",bo\ol=false,duration="4h24m3s",float32=80,float64=80.1234567,int=-1234567890i,int16=-3456i,int32=-34567i,int64=-1234567890i,int8=-34i,stri\=ng="six=seven\\, eight",time="2020-03-20T10:30:23.123456789Z",uint=12345677890u,uint\ 64=41234567890u,uint16=3456u,uint32=34578u,uint8=34u 60000000070`)
  160. }
  161. func TestPointAdd(t *testing.T) {
  162. p := NewPointWithMeasurement("test")
  163. p.AddTag("id", "10ad=")
  164. p.AddTag("ven=dor", "AWS")
  165. p.AddTag(`host"name`, "host_a")
  166. //test re-setting same tag
  167. p.AddTag(`host"name`, `ho\st "a"`)
  168. p.AddTag(`x\" x`, "a b")
  169. p.SortTags()
  170. p.AddField("float64", 80.1234567)
  171. p.AddField("float32", float32(80.0))
  172. p.AddField("int", -1234567890)
  173. p.AddField("int8", int8(-34))
  174. p.AddField("int16", int16(-3456))
  175. p.AddField("int32", int32(-34567))
  176. p.AddField("int64", int64(-1234567890))
  177. p.AddField("uint", uint(12345677890))
  178. p.AddField("uint8", uint8(34))
  179. p.AddField("uint16", uint16(3456))
  180. p.AddField("uint32", uint32(34578))
  181. p.AddField("uint 64", uint64(0))
  182. // test re-setting same field
  183. p.AddField("uint 64", uint64(41234567890))
  184. p.AddField("bo\\ol", false)
  185. p.AddField(`"string"`, `six, "seven", eight`)
  186. p.AddField("stri=ng", `six=seven\, eight`)
  187. p.AddField("time", time.Date(2020, time.March, 20, 10, 30, 23, 123456789, time.UTC))
  188. p.AddField("duration", time.Duration(4*time.Hour+24*time.Minute+3*time.Second))
  189. p.SortFields()
  190. p.SetTime(time.Unix(60, 70))
  191. verifyPoint(t, p)
  192. }
  193. func TestPointFluent(t *testing.T) {
  194. p := NewPointWithMeasurement("test").
  195. AddTag("id", "10ad=").
  196. AddTag("ven=dor", "AWS").
  197. AddTag(`host"name`, "host_a").
  198. //test re-setting same tag
  199. AddTag(`host"name`, `ho\st "a"`).
  200. AddTag(`x\" x`, "a b").
  201. SortTags().
  202. AddField("float64", 80.1234567).
  203. AddField("float32", float32(80.0)).
  204. AddField("int", -1234567890).
  205. AddField("int8", int8(-34)).
  206. AddField("int16", int16(-3456)).
  207. AddField("int32", int32(-34567)).
  208. AddField("int64", int64(-1234567890)).
  209. AddField("uint", uint(12345677890)).
  210. AddField("uint8", uint8(34)).
  211. AddField("uint16", uint16(3456)).
  212. AddField("uint32", uint32(34578)).
  213. AddField("uint 64", uint64(0)).
  214. // test re-setting same field
  215. AddField("uint 64", uint64(41234567890)).
  216. AddField("bo\\ol", false).
  217. AddField(`"string"`, `six, "seven", eight`).
  218. AddField("stri=ng", `six=seven\, eight`).
  219. AddField("time", time.Date(2020, time.March, 20, 10, 30, 23, 123456789, time.UTC)).
  220. AddField("duration", time.Duration(4*time.Hour+24*time.Minute+3*time.Second)).
  221. SortFields().
  222. SetTime(time.Unix(60, 70))
  223. verifyPoint(t, p)
  224. }
  225. func TestPrecision(t *testing.T) {
  226. p := NewPointWithMeasurement("test")
  227. p.AddTag("id", "10")
  228. p.AddField("float64", 80.1234567)
  229. p.SetTime(time.Unix(60, 89))
  230. line := PointToLineProtocol(p, time.Nanosecond)
  231. assert.Equal(t, line, "test,id=10 float64=80.1234567 60000000089\n")
  232. p.SetTime(time.Unix(60, 56789))
  233. line = PointToLineProtocol(p, time.Microsecond)
  234. assert.Equal(t, line, "test,id=10 float64=80.1234567 60000056\n")
  235. p.SetTime(time.Unix(60, 123456789))
  236. line = PointToLineProtocol(p, time.Millisecond)
  237. assert.Equal(t, line, "test,id=10 float64=80.1234567 60123\n")
  238. p.SetTime(time.Unix(60, 123456789))
  239. line = PointToLineProtocol(p, time.Second)
  240. assert.Equal(t, line, "test,id=10 float64=80.1234567 60\n")
  241. }
  242. func TestTagEscapingKeyAndValue(t *testing.T) {
  243. p := NewPointWithMeasurement("h\n2\no\t_data")
  244. p.AddTag("new\nline", "new\nline")
  245. p.AddTag("carriage\rreturn", "carriage\rreturn")
  246. p.AddTag("t\tab", "t\tab")
  247. p.AddField("level", 2)
  248. line := PointToLineProtocol(p, time.Nanosecond)
  249. assert.Equal(t, "h\\\\n2\\\\no\\\\t_data,new\\\\nline=new\\\\nline,carriage\\\\rreturn=carriage\\\\rreturn,t\\\\tab=t\\\\tab level=2i\n", line)
  250. }
  251. func TestEqualSignEscaping(t *testing.T) {
  252. p := NewPointWithMeasurement("h=2o")
  253. p.AddTag("l=ocation", "e=urope")
  254. p.AddField("l=evel", 2)
  255. line := PointToLineProtocol(p, time.Nanosecond)
  256. assert.Equal(t, "h=2o,l\\=ocation=e\\=urope l\\=evel=2i\n", line)
  257. }
  258. var s string
  259. func BenchmarkPointEncoderSingle(b *testing.B) {
  260. for n := 0; n < b.N; n++ {
  261. var buff strings.Builder
  262. for _, p := range points {
  263. var buffer bytes.Buffer
  264. e := lp.NewEncoder(&buffer)
  265. _, _ = e.Encode(p)
  266. buff.WriteString(buffer.String())
  267. }
  268. s = buff.String()
  269. }
  270. }
  271. func BenchmarkPointEncoderMulti(b *testing.B) {
  272. for n := 0; n < b.N; n++ {
  273. var buffer bytes.Buffer
  274. e := lp.NewEncoder(&buffer)
  275. for _, p := range points {
  276. _, _ = e.Encode(p)
  277. }
  278. s = buffer.String()
  279. }
  280. }
  281. func BenchmarkPointStringSingle(b *testing.B) {
  282. for n := 0; n < b.N; n++ {
  283. var buff strings.Builder
  284. for _, p := range points {
  285. buff.WriteString(PointToLineProtocol(p, time.Nanosecond))
  286. }
  287. s = buff.String()
  288. }
  289. }
  290. func BenchmarkPointStringMulti(b *testing.B) {
  291. for n := 0; n < b.N; n++ {
  292. var buff strings.Builder
  293. for _, p := range points {
  294. PointToLineProtocolBuffer(p, &buff, time.Nanosecond)
  295. }
  296. s = buff.String()
  297. }
  298. }