@quenty/influxdbclient 7.37.0 → 7.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,373 @@
1
+ --!strict
2
+ --[[
3
+ @class InfluxDBPoint.spec.lua
4
+ ]]
5
+
6
+ local require = require(script.Parent.loader).load(script)
7
+
8
+ local InfluxDBPoint = require("InfluxDBPoint")
9
+ local InfluxDBPointSettings = require("InfluxDBPointSettings")
10
+ local Jest = require("Jest")
11
+
12
+ local describe = Jest.Globals.describe
13
+ local expect = Jest.Globals.expect
14
+ local it = Jest.Globals.it
15
+
16
+ -- A fixed timestamp keeps line protocol output deterministic across tests.
17
+ local FIXED_TIMESTAMP = DateTime.fromUnixTimestampMillis(1600000000000)
18
+
19
+ local function newFixedPoint(measurementName: string?): InfluxDBPoint.InfluxDBPoint
20
+ local point = InfluxDBPoint.new(measurementName)
21
+ point:SetTimestamp(FIXED_TIMESTAMP)
22
+ return point
23
+ end
24
+
25
+ describe("InfluxDBPoint.new", function()
26
+ it("should default to an empty set of tags and fields", function()
27
+ local point = InfluxDBPoint.new("temperature")
28
+ local data = point:ToTableData()
29
+
30
+ expect(next(data.tags)).toEqual(nil)
31
+ expect(next(data.fields)).toEqual(nil)
32
+ end)
33
+
34
+ it("should allow a nil measurement name", function()
35
+ local point = InfluxDBPoint.new()
36
+ expect(point:GetMeasurementName()).toEqual(nil)
37
+ end)
38
+
39
+ it("should default the timestamp to a numeric millisecond string", function()
40
+ local point = InfluxDBPoint.new("temperature")
41
+ local timestamp = point:ToTableData().timestamp
42
+
43
+ expect(type(timestamp)).toEqual("string")
44
+ expect(tonumber(timestamp)).never.toEqual(nil)
45
+ end)
46
+
47
+ it("should throw on a non-string measurement name", function()
48
+ expect(function()
49
+ InfluxDBPoint.new(5 :: any)
50
+ end).toThrow("Bad measurementName")
51
+ end)
52
+ end)
53
+
54
+ describe("InfluxDBPoint.isInfluxDBPoint", function()
55
+ it("should be true for a point", function()
56
+ expect(InfluxDBPoint.isInfluxDBPoint(InfluxDBPoint.new("temperature"))).toEqual(true)
57
+ end)
58
+
59
+ it("should be false for a plain table", function()
60
+ expect(InfluxDBPoint.isInfluxDBPoint({})).toEqual(false)
61
+ end)
62
+
63
+ it("should be false for nil and primitives", function()
64
+ expect(InfluxDBPoint.isInfluxDBPoint(nil)).toEqual(false)
65
+ expect(InfluxDBPoint.isInfluxDBPoint(5)).toEqual(false)
66
+ expect(InfluxDBPoint.isInfluxDBPoint("str")).toEqual(false)
67
+ end)
68
+ end)
69
+
70
+ describe("InfluxDBPoint measurement name", function()
71
+ it("should get and set the measurement name", function()
72
+ local point = InfluxDBPoint.new("temperature")
73
+ expect(point:GetMeasurementName()).toEqual("temperature")
74
+
75
+ point:SetMeasurementName("humidity")
76
+ expect(point:GetMeasurementName()).toEqual("humidity")
77
+ end)
78
+ end)
79
+
80
+ describe("InfluxDBPoint.AddTag", function()
81
+ it("should throw on a non-string key", function()
82
+ local point = InfluxDBPoint.new("temperature")
83
+ expect(function()
84
+ point:AddTag(5 :: any, "value")
85
+ end).toThrow("Bad tagKey")
86
+ end)
87
+
88
+ it("should throw on a non-string value", function()
89
+ local point = InfluxDBPoint.new("temperature")
90
+ expect(function()
91
+ point:AddTag("key", 5 :: any)
92
+ end).toThrow("Bad tagValue")
93
+ end)
94
+ end)
95
+
96
+ describe("InfluxDBPoint field setters", function()
97
+ it("should add an int field with an 'i' suffix", function()
98
+ local point = newFixedPoint("temperature")
99
+ point:AddIntField("count", 5)
100
+
101
+ expect(point:ToLineProtocol(InfluxDBPointSettings.new())).toEqual("temperature count=5i 1600000000000")
102
+ end)
103
+
104
+ it("should add a uint field with a 'u' suffix", function()
105
+ local point = newFixedPoint("temperature")
106
+ point:AddUintField("count", 5)
107
+
108
+ expect(point:ToLineProtocol(InfluxDBPointSettings.new())).toEqual("temperature count=5u 1600000000000")
109
+ end)
110
+
111
+ it("should add a float field verbatim", function()
112
+ local point = newFixedPoint("temperature")
113
+ point:AddFloatField("value", 23.5)
114
+
115
+ expect(point:ToLineProtocol(InfluxDBPointSettings.new())).toEqual("temperature value=23.5 1600000000000")
116
+ end)
117
+
118
+ it("should add a boolean field as T or F", function()
119
+ local truePoint = newFixedPoint("temperature")
120
+ truePoint:AddBooleanField("active", true)
121
+ expect(truePoint:ToLineProtocol(InfluxDBPointSettings.new())).toEqual("temperature active=T 1600000000000")
122
+
123
+ local falsePoint = newFixedPoint("temperature")
124
+ falsePoint:AddBooleanField("active", false)
125
+ expect(falsePoint:ToLineProtocol(InfluxDBPointSettings.new())).toEqual("temperature active=F 1600000000000")
126
+ end)
127
+
128
+ it("should add a quoted string field", function()
129
+ local point = newFixedPoint("temperature")
130
+ point:AddStringField("message", "hello")
131
+
132
+ expect(point:ToLineProtocol(InfluxDBPointSettings.new())).toEqual('temperature message="hello" 1600000000000')
133
+ end)
134
+
135
+ it("should escape quotes in a string field value", function()
136
+ local point = newFixedPoint("temperature")
137
+ point:AddStringField("message", 'he said "hi"')
138
+
139
+ expect(point:ToLineProtocol(InfluxDBPointSettings.new())).toEqual(
140
+ 'temperature message="he said \\"hi\\"" 1600000000000'
141
+ )
142
+ end)
143
+
144
+ it("should throw on a non-number int value", function()
145
+ local point = InfluxDBPoint.new("temperature")
146
+ expect(function()
147
+ point:AddIntField("count", "5" :: any)
148
+ end).toThrow("Bad value")
149
+ end)
150
+
151
+ it("should throw on a NaN int value", function()
152
+ local point = InfluxDBPoint.new("temperature")
153
+ expect(function()
154
+ point:AddIntField("count", 0 / 0)
155
+ end).toThrow("invalid integer value")
156
+ end)
157
+
158
+ it("should throw on an out-of-range int value", function()
159
+ local point = InfluxDBPoint.new("temperature")
160
+ expect(function()
161
+ point:AddIntField("count", 1e30)
162
+ end).toThrow("invalid integer value")
163
+ end)
164
+
165
+ it("should throw on a negative uint value", function()
166
+ local point = InfluxDBPoint.new("temperature")
167
+ expect(function()
168
+ point:AddUintField("count", -1)
169
+ end).toThrow("invalid uint value")
170
+ end)
171
+
172
+ it("should throw on an out-of-range uint value", function()
173
+ local point = InfluxDBPoint.new("temperature")
174
+ expect(function()
175
+ point:AddUintField("count", 9007199254740991)
176
+ end).toThrow("invalid uint value")
177
+ end)
178
+
179
+ it("should throw on an infinite float value", function()
180
+ local point = InfluxDBPoint.new("temperature")
181
+ expect(function()
182
+ point:AddFloatField("value", math.huge)
183
+ end).toThrow("invalid float value")
184
+ end)
185
+
186
+ it("should throw on a non-boolean boolean value", function()
187
+ local point = InfluxDBPoint.new("temperature")
188
+ expect(function()
189
+ point:AddBooleanField("active", "true" :: any)
190
+ end).toThrow("Bad value")
191
+ end)
192
+ end)
193
+
194
+ describe("InfluxDBPoint.ToLineProtocol", function()
195
+ it("should return nil without a measurement name", function()
196
+ local point = newFixedPoint()
197
+ point:AddIntField("count", 5)
198
+
199
+ expect(point:ToLineProtocol(InfluxDBPointSettings.new())).toEqual(nil)
200
+ end)
201
+
202
+ it("should return nil without any fields", function()
203
+ local point = newFixedPoint("temperature")
204
+
205
+ expect(point:ToLineProtocol(InfluxDBPointSettings.new())).toEqual(nil)
206
+ end)
207
+
208
+ it("should render tags before the field set", function()
209
+ local point = newFixedPoint("temperature")
210
+ point:AddTag("location", "office")
211
+ point:AddFloatField("value", 23.5)
212
+
213
+ expect(point:ToLineProtocol(InfluxDBPointSettings.new())).toEqual(
214
+ "temperature,location=office value=23.5 1600000000000"
215
+ )
216
+ end)
217
+
218
+ it("should sort field keys alphabetically", function()
219
+ local point = newFixedPoint("temperature")
220
+ point:AddIntField("zeta", 1)
221
+ point:AddIntField("alpha", 2)
222
+
223
+ expect(point:ToLineProtocol(InfluxDBPointSettings.new())).toEqual("temperature alpha=2i,zeta=1i 1600000000000")
224
+ end)
225
+
226
+ it("should sort tag keys alphabetically", function()
227
+ local point = newFixedPoint("temperature")
228
+ point:AddTag("zeta", "z")
229
+ point:AddTag("alpha", "a")
230
+ point:AddFloatField("value", 1)
231
+
232
+ expect(point:ToLineProtocol(InfluxDBPointSettings.new())).toEqual(
233
+ "temperature,alpha=a,zeta=z value=1 1600000000000"
234
+ )
235
+ end)
236
+
237
+ it("should escape spaces in the measurement name", function()
238
+ local point = newFixedPoint("my measurement")
239
+ point:AddFloatField("value", 1)
240
+
241
+ expect(point:ToLineProtocol(InfluxDBPointSettings.new())).toEqual("my\\ measurement value=1 1600000000000")
242
+ end)
243
+
244
+ it("should escape special characters in tag keys and values", function()
245
+ local point = newFixedPoint("temperature")
246
+ point:AddTag("my tag", "a,b")
247
+ point:AddFloatField("value", 1)
248
+
249
+ expect(point:ToLineProtocol(InfluxDBPointSettings.new())).toEqual(
250
+ "temperature,my\\ tag=a\\,b value=1 1600000000000"
251
+ )
252
+ end)
253
+
254
+ it("should merge default tags from the point settings", function()
255
+ local point = newFixedPoint("temperature")
256
+ point:AddTag("location", "office")
257
+ point:AddFloatField("value", 1)
258
+
259
+ local settings = InfluxDBPointSettings.new()
260
+ settings:SetDefaultTags({ host = "server1" })
261
+
262
+ expect(point:ToLineProtocol(settings)).toEqual("temperature,host=server1,location=office value=1 1600000000000")
263
+ end)
264
+
265
+ it("should prefer the point's own tag over a default tag of the same key", function()
266
+ local point = newFixedPoint("temperature")
267
+ point:AddTag("host", "override")
268
+ point:AddFloatField("value", 1)
269
+
270
+ local settings = InfluxDBPointSettings.new()
271
+ settings:SetDefaultTags({ host = "default" })
272
+
273
+ expect(point:ToLineProtocol(settings)).toEqual("temperature,host=override value=1 1600000000000")
274
+ end)
275
+
276
+ it("should apply the convert time function to the timestamp", function()
277
+ local point = newFixedPoint("temperature")
278
+ point:AddFloatField("value", 1)
279
+
280
+ local settings = InfluxDBPointSettings.new()
281
+ settings:SetConvertTime(function(_timestamp)
282
+ return 999
283
+ end)
284
+
285
+ expect(point:ToLineProtocol(settings)).toEqual("temperature value=1 999")
286
+ end)
287
+ end)
288
+
289
+ describe("InfluxDBPoint.SetTimestamp", function()
290
+ it("should throw on a non-DateTime, non-nil timestamp", function()
291
+ local point = InfluxDBPoint.new("temperature")
292
+ expect(function()
293
+ point:SetTimestamp(5 :: any)
294
+ end).toThrow("Bad timestamp")
295
+ end)
296
+ end)
297
+
298
+ describe("InfluxDBPoint.ToTableData", function()
299
+ it("should round-trip through fromTableData", function()
300
+ local point = newFixedPoint("temperature")
301
+ point:AddTag("location", "office")
302
+ point:AddIntField("count", 5)
303
+
304
+ local copy = InfluxDBPoint.fromTableData(point:ToTableData())
305
+
306
+ expect(copy:GetMeasurementName()).toEqual("temperature")
307
+ expect(copy:ToLineProtocol(InfluxDBPointSettings.new())).toEqual(
308
+ point:ToLineProtocol(InfluxDBPointSettings.new())
309
+ )
310
+ end)
311
+
312
+ it("should return clones that do not mutate the source point", function()
313
+ local point = InfluxDBPoint.new("temperature")
314
+ point:AddTag("location", "office")
315
+
316
+ local data = point:ToTableData()
317
+ data.tags.location = "mutated"
318
+
319
+ expect(point:ToTableData().tags.location).toEqual("office")
320
+ end)
321
+ end)
322
+
323
+ describe("InfluxDBPoint.fromTableData", function()
324
+ it("should build a point from table data", function()
325
+ local point = InfluxDBPoint.fromTableData({
326
+ measurementName = "temperature",
327
+ timestamp = 1600000000000,
328
+ tags = { location = "office" },
329
+ fields = { count = "5i" },
330
+ })
331
+
332
+ expect(point:GetMeasurementName()).toEqual("temperature")
333
+ expect(point:ToLineProtocol(InfluxDBPointSettings.new())).toEqual(
334
+ "temperature,location=office count=5i 1600000000000"
335
+ )
336
+ end)
337
+
338
+ it("should throw on non-table data", function()
339
+ expect(function()
340
+ InfluxDBPoint.fromTableData(5 :: any)
341
+ end).toThrow("Bad data")
342
+ end)
343
+
344
+ it("should throw on a non-string measurement name", function()
345
+ expect(function()
346
+ InfluxDBPoint.fromTableData({
347
+ measurementName = 5 :: any,
348
+ tags = {},
349
+ fields = {},
350
+ })
351
+ end).toThrow("Bad data.measurementName")
352
+ end)
353
+
354
+ it("should throw on a non-string tag value", function()
355
+ expect(function()
356
+ InfluxDBPoint.fromTableData({
357
+ measurementName = "temperature",
358
+ tags = { location = 5 :: any },
359
+ fields = {},
360
+ })
361
+ end).toThrow("Bad tagValue")
362
+ end)
363
+
364
+ it("should throw on a non-string field value", function()
365
+ expect(function()
366
+ InfluxDBPoint.fromTableData({
367
+ measurementName = "temperature",
368
+ tags = {},
369
+ fields = { count = 5 :: any },
370
+ })
371
+ end).toThrow("Bad fieldValue")
372
+ end)
373
+ end)