@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.
- package/CHANGELOG.md +10 -0
- package/package.json +2 -2
- package/src/Server/Config/InfluxDBClientConfigUtils.spec.lua +86 -0
- package/src/Server/Config/InfluxDBWriteOptionUtils.spec.lua +94 -0
- package/src/Server/InfluxDBClient.lua +45 -3
- package/src/Server/InfluxDBClient.spec.lua +227 -0
- package/src/Server/InfluxDBService.lua +147 -0
- package/src/Server/InfluxDBService.spec.lua +151 -0
- package/src/Server/Mocks/InfluxDBRequestHandlerMock.lua +132 -0
- package/src/Server/Mocks/InfluxDBRequestHandlerMock.spec.lua +107 -0
- package/src/Server/Utils/InfluxDBErrorUtils.spec.lua +69 -0
- package/src/Server/Write/InfluxDBWriteAPI.lua +21 -2
- package/src/Server/Write/InfluxDBWriteAPI.spec.lua +322 -0
- package/src/Server/Write/InfluxDBWriteBuffer.spec.lua +144 -0
- package/src/Shared/Config/InfluxDBPointSettings.spec.lua +87 -0
- package/src/Shared/Utils/InfluxDBEscapeUtils.spec.lua +70 -0
- package/src/Shared/Write/InfluxDBPoint.spec.lua +373 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--[[
|
|
3
|
+
@class InfluxDBService.spec.lua
|
|
4
|
+
]]
|
|
5
|
+
|
|
6
|
+
local require = require(script.Parent.loader).load(script)
|
|
7
|
+
|
|
8
|
+
local InfluxDBPoint = require("InfluxDBPoint")
|
|
9
|
+
local InfluxDBRequestHandlerMock = require("InfluxDBRequestHandlerMock")
|
|
10
|
+
local InfluxDBService = require("InfluxDBService")
|
|
11
|
+
local Jest = require("Jest")
|
|
12
|
+
local PromiseTestUtils = require("PromiseTestUtils")
|
|
13
|
+
local ServiceBag = require("ServiceBag")
|
|
14
|
+
|
|
15
|
+
local describe = Jest.Globals.describe
|
|
16
|
+
local expect = Jest.Globals.expect
|
|
17
|
+
local it = Jest.Globals.it
|
|
18
|
+
|
|
19
|
+
local FIXED_TIMESTAMP = DateTime.fromUnixTimestampMillis(1600000000000)
|
|
20
|
+
|
|
21
|
+
local CONFIG = {
|
|
22
|
+
url = "https://example.com",
|
|
23
|
+
token = "my-token",
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
local function newPoint(): InfluxDBPoint.InfluxDBPoint
|
|
27
|
+
local point = InfluxDBPoint.new("temperature")
|
|
28
|
+
point:SetTimestamp(FIXED_TIMESTAMP)
|
|
29
|
+
point:AddFloatField("value", 23.5)
|
|
30
|
+
return point
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
-- Boots a service through a ServiceBag with a request mock injected between Init and Start, mirroring
|
|
34
|
+
-- how a consuming package would swap in the mock at the ServiceBag layer.
|
|
35
|
+
local function setup()
|
|
36
|
+
local serviceBag = ServiceBag.new()
|
|
37
|
+
local influxDBService = (serviceBag:GetService(InfluxDBService) :: any) :: InfluxDBService.InfluxDBService
|
|
38
|
+
serviceBag:Init()
|
|
39
|
+
|
|
40
|
+
local requestMock = InfluxDBRequestHandlerMock.new()
|
|
41
|
+
influxDBService:SetRequestHandler(requestMock.Handler)
|
|
42
|
+
|
|
43
|
+
serviceBag:Start()
|
|
44
|
+
|
|
45
|
+
return serviceBag, influxDBService, requestMock
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe("InfluxDBService.SetRequestHandler", function()
|
|
49
|
+
it("should route write traffic through the injected mock", function()
|
|
50
|
+
local serviceBag, influxDBService, requestMock = setup()
|
|
51
|
+
influxDBService:SetClientConfig(CONFIG)
|
|
52
|
+
|
|
53
|
+
local writeAPI = influxDBService:GetWriteAPI("my-org", "my-bucket")
|
|
54
|
+
writeAPI:QueuePoint(newPoint())
|
|
55
|
+
expect(PromiseTestUtils.awaitSettled(writeAPI:PromiseFlush())).toEqual(true)
|
|
56
|
+
|
|
57
|
+
expect(#requestMock:GetRequests()).toEqual(1)
|
|
58
|
+
expect((requestMock:GetLastRequest() :: any).Headers.Authorization).toEqual("Token my-token")
|
|
59
|
+
|
|
60
|
+
serviceBag:Destroy()
|
|
61
|
+
end)
|
|
62
|
+
|
|
63
|
+
it("should throw on a non-function handler", function()
|
|
64
|
+
local serviceBag = ServiceBag.new()
|
|
65
|
+
local influxDBService = (serviceBag:GetService(InfluxDBService) :: any) :: InfluxDBService.InfluxDBService
|
|
66
|
+
serviceBag:Init()
|
|
67
|
+
|
|
68
|
+
expect(function()
|
|
69
|
+
influxDBService:SetRequestHandler(5 :: any)
|
|
70
|
+
end).toThrow("Bad requestHandler")
|
|
71
|
+
|
|
72
|
+
serviceBag:Destroy()
|
|
73
|
+
end)
|
|
74
|
+
|
|
75
|
+
it("should throw once the client has been built", function()
|
|
76
|
+
local serviceBag = ServiceBag.new()
|
|
77
|
+
local influxDBService = (serviceBag:GetService(InfluxDBService) :: any) :: InfluxDBService.InfluxDBService
|
|
78
|
+
serviceBag:Init()
|
|
79
|
+
serviceBag:Start()
|
|
80
|
+
|
|
81
|
+
-- Building the client locks the seam.
|
|
82
|
+
influxDBService:GetClient()
|
|
83
|
+
|
|
84
|
+
expect(function()
|
|
85
|
+
influxDBService:SetRequestHandler(InfluxDBRequestHandlerMock.new().Handler)
|
|
86
|
+
end).toThrow("Already built client")
|
|
87
|
+
|
|
88
|
+
serviceBag:Destroy()
|
|
89
|
+
end)
|
|
90
|
+
end)
|
|
91
|
+
|
|
92
|
+
describe("InfluxDBService.SetClientConfig", function()
|
|
93
|
+
it("should throw on an invalid config", function()
|
|
94
|
+
local serviceBag, influxDBService = setup()
|
|
95
|
+
|
|
96
|
+
expect(function()
|
|
97
|
+
influxDBService:SetClientConfig({ url = "https://example.com" } :: any)
|
|
98
|
+
end).toThrow("Bad clientConfig")
|
|
99
|
+
|
|
100
|
+
serviceBag:Destroy()
|
|
101
|
+
end)
|
|
102
|
+
|
|
103
|
+
it("should apply a config set after the client is built", function()
|
|
104
|
+
local serviceBag, influxDBService, requestMock = setup()
|
|
105
|
+
|
|
106
|
+
-- Build the client and its write API before any config is set.
|
|
107
|
+
local writeAPI = influxDBService:GetWriteAPI("my-org", "my-bucket")
|
|
108
|
+
|
|
109
|
+
influxDBService:SetClientConfig(CONFIG)
|
|
110
|
+
|
|
111
|
+
writeAPI:QueuePoint(newPoint())
|
|
112
|
+
expect(PromiseTestUtils.awaitSettled(writeAPI:PromiseFlush())).toEqual(true)
|
|
113
|
+
|
|
114
|
+
expect(#requestMock:GetRequests()).toEqual(1)
|
|
115
|
+
|
|
116
|
+
serviceBag:Destroy()
|
|
117
|
+
end)
|
|
118
|
+
end)
|
|
119
|
+
|
|
120
|
+
describe("InfluxDBService.GetClient", function()
|
|
121
|
+
it("should return the same client across calls", function()
|
|
122
|
+
local serviceBag, influxDBService = setup()
|
|
123
|
+
|
|
124
|
+
expect(influxDBService:GetClient()).toBe(influxDBService:GetClient())
|
|
125
|
+
|
|
126
|
+
serviceBag:Destroy()
|
|
127
|
+
end)
|
|
128
|
+
end)
|
|
129
|
+
|
|
130
|
+
describe("InfluxDBService.PromiseFlushAll", function()
|
|
131
|
+
it("should resolve when the client was never built", function()
|
|
132
|
+
local serviceBag, influxDBService = setup()
|
|
133
|
+
|
|
134
|
+
expect(PromiseTestUtils.awaitSettled(influxDBService:PromiseFlushAll())).toEqual(true)
|
|
135
|
+
|
|
136
|
+
serviceBag:Destroy()
|
|
137
|
+
end)
|
|
138
|
+
|
|
139
|
+
it("should flush buffered points once the client is built", function()
|
|
140
|
+
local serviceBag, influxDBService, requestMock = setup()
|
|
141
|
+
influxDBService:SetClientConfig(CONFIG)
|
|
142
|
+
|
|
143
|
+
local writeAPI = influxDBService:GetWriteAPI("my-org", "my-bucket")
|
|
144
|
+
writeAPI:QueuePoint(newPoint())
|
|
145
|
+
|
|
146
|
+
expect(PromiseTestUtils.awaitSettled(influxDBService:PromiseFlushAll())).toEqual(true)
|
|
147
|
+
expect(#requestMock:GetRequests()).toEqual(1)
|
|
148
|
+
|
|
149
|
+
serviceBag:Destroy()
|
|
150
|
+
end)
|
|
151
|
+
end)
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--[=[
|
|
3
|
+
In-memory stand-in for [HttpPromise.request] used to test InfluxDB writes without making real HTTP
|
|
4
|
+
calls. Inject its [InfluxDBRequestHandlerMock.Handler] wherever an [InfluxDBRequestHandler] is
|
|
5
|
+
expected -- into [InfluxDBClient.new], via [InfluxDBService.SetRequestHandler], or use
|
|
6
|
+
[InfluxDBClient.newMock], which wires one up for you.
|
|
7
|
+
|
|
8
|
+
Every request handed to the mock is recorded for inspection. By default each request resolves with a
|
|
9
|
+
204 success response; call [InfluxDBRequestHandlerMock.SetResponder] to control the response (for
|
|
10
|
+
example to simulate a failure).
|
|
11
|
+
|
|
12
|
+
```lua
|
|
13
|
+
local requestMock = InfluxDBRequestHandlerMock.new()
|
|
14
|
+
local client = InfluxDBClient.new(config, requestMock.Handler)
|
|
15
|
+
-- ...write some points...
|
|
16
|
+
print(#requestMock:GetRequests())
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
@server
|
|
20
|
+
@class InfluxDBRequestHandlerMock
|
|
21
|
+
]=]
|
|
22
|
+
|
|
23
|
+
local require = require(script.Parent.loader).load(script)
|
|
24
|
+
|
|
25
|
+
local HttpPromise = require("HttpPromise")
|
|
26
|
+
local Promise = require("Promise")
|
|
27
|
+
|
|
28
|
+
local InfluxDBRequestHandlerMock = {}
|
|
29
|
+
InfluxDBRequestHandlerMock.ClassName = "InfluxDBRequestHandlerMock"
|
|
30
|
+
InfluxDBRequestHandlerMock.__index = InfluxDBRequestHandlerMock
|
|
31
|
+
|
|
32
|
+
--[=[
|
|
33
|
+
A responder controls how the mock answers a request, so a test can resolve or reject however it needs.
|
|
34
|
+
|
|
35
|
+
@type Responder (request: HttpPromise.HTTPRequest) -> Promise<HttpPromise.HTTPResponse>
|
|
36
|
+
@within InfluxDBRequestHandlerMock
|
|
37
|
+
]=]
|
|
38
|
+
export type Responder = (request: HttpPromise.HTTPRequest) -> Promise.Promise<HttpPromise.HTTPResponse>
|
|
39
|
+
|
|
40
|
+
export type InfluxDBRequestHandlerMock = typeof(setmetatable(
|
|
41
|
+
{} :: {
|
|
42
|
+
-- The request handler function to inject; recording is done through it.
|
|
43
|
+
Handler: Responder,
|
|
44
|
+
_requests: { HttpPromise.HTTPRequest },
|
|
45
|
+
_responder: Responder?,
|
|
46
|
+
},
|
|
47
|
+
{} :: typeof({ __index = InfluxDBRequestHandlerMock })
|
|
48
|
+
))
|
|
49
|
+
|
|
50
|
+
local function defaultResponse(): HttpPromise.HTTPResponse
|
|
51
|
+
return {
|
|
52
|
+
Success = true,
|
|
53
|
+
StatusCode = 204,
|
|
54
|
+
StatusMessage = "No Content",
|
|
55
|
+
Headers = {},
|
|
56
|
+
Body = "",
|
|
57
|
+
}
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
--[=[
|
|
61
|
+
Returns whether the given value is an [InfluxDBRequestHandlerMock].
|
|
62
|
+
|
|
63
|
+
@param value any
|
|
64
|
+
@return boolean
|
|
65
|
+
]=]
|
|
66
|
+
function InfluxDBRequestHandlerMock.isInfluxDBRequestHandlerMock(value: any): boolean
|
|
67
|
+
return type(value) == "table" and getmetatable(value) == InfluxDBRequestHandlerMock
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
--[=[
|
|
71
|
+
Constructs a new InfluxDBRequestHandlerMock.
|
|
72
|
+
|
|
73
|
+
@return InfluxDBRequestHandlerMock
|
|
74
|
+
]=]
|
|
75
|
+
function InfluxDBRequestHandlerMock.new(): InfluxDBRequestHandlerMock
|
|
76
|
+
local self: InfluxDBRequestHandlerMock = setmetatable({} :: any, InfluxDBRequestHandlerMock)
|
|
77
|
+
|
|
78
|
+
self._requests = {}
|
|
79
|
+
self._responder = nil
|
|
80
|
+
|
|
81
|
+
-- Bound closure so it can be passed wherever a plain [InfluxDBRequestHandler] function is expected.
|
|
82
|
+
self.Handler = function(request)
|
|
83
|
+
return self:_handleRequest(request)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
return self
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
function InfluxDBRequestHandlerMock._handleRequest(
|
|
90
|
+
self: InfluxDBRequestHandlerMock,
|
|
91
|
+
request: HttpPromise.HTTPRequest
|
|
92
|
+
): Promise.Promise<HttpPromise.HTTPResponse>
|
|
93
|
+
table.insert(self._requests, request)
|
|
94
|
+
|
|
95
|
+
if self._responder then
|
|
96
|
+
return self._responder(request)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
return Promise.resolved(defaultResponse())
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
--[=[
|
|
103
|
+
Sets a responder invoked for each subsequent request, letting a test resolve or reject however it
|
|
104
|
+
needs. Pass nil to restore the default 204 success response.
|
|
105
|
+
|
|
106
|
+
@param responder Responder?
|
|
107
|
+
]=]
|
|
108
|
+
function InfluxDBRequestHandlerMock.SetResponder(self: InfluxDBRequestHandlerMock, responder: Responder?): ()
|
|
109
|
+
assert(type(responder) == "function" or responder == nil, "Bad responder")
|
|
110
|
+
|
|
111
|
+
self._responder = responder
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
--[=[
|
|
115
|
+
Returns every request handed to the mock, in order.
|
|
116
|
+
|
|
117
|
+
@return { HttpPromise.HTTPRequest }
|
|
118
|
+
]=]
|
|
119
|
+
function InfluxDBRequestHandlerMock.GetRequests(self: InfluxDBRequestHandlerMock): { HttpPromise.HTTPRequest }
|
|
120
|
+
return self._requests
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
--[=[
|
|
124
|
+
Returns the most recent request handed to the mock, or nil if there have been none.
|
|
125
|
+
|
|
126
|
+
@return HttpPromise.HTTPRequest?
|
|
127
|
+
]=]
|
|
128
|
+
function InfluxDBRequestHandlerMock.GetLastRequest(self: InfluxDBRequestHandlerMock): HttpPromise.HTTPRequest?
|
|
129
|
+
return self._requests[#self._requests]
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
return InfluxDBRequestHandlerMock
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--[[
|
|
3
|
+
@class InfluxDBRequestHandlerMock.spec.lua
|
|
4
|
+
]]
|
|
5
|
+
|
|
6
|
+
local require = require(script.Parent.loader).load(script)
|
|
7
|
+
|
|
8
|
+
local InfluxDBRequestHandlerMock = require("InfluxDBRequestHandlerMock")
|
|
9
|
+
local Jest = require("Jest")
|
|
10
|
+
local Promise = require("Promise")
|
|
11
|
+
local PromiseTestUtils = require("PromiseTestUtils")
|
|
12
|
+
|
|
13
|
+
local describe = Jest.Globals.describe
|
|
14
|
+
local expect = Jest.Globals.expect
|
|
15
|
+
local it = Jest.Globals.it
|
|
16
|
+
|
|
17
|
+
local function request(url: string): any
|
|
18
|
+
return {
|
|
19
|
+
Method = "POST",
|
|
20
|
+
Url = url,
|
|
21
|
+
Headers = {},
|
|
22
|
+
Body = "",
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe("InfluxDBRequestHandlerMock.isInfluxDBRequestHandlerMock", function()
|
|
27
|
+
it("should be true for a mock", function()
|
|
28
|
+
expect(InfluxDBRequestHandlerMock.isInfluxDBRequestHandlerMock(InfluxDBRequestHandlerMock.new())).toEqual(true)
|
|
29
|
+
end)
|
|
30
|
+
|
|
31
|
+
it("should be false for other values", function()
|
|
32
|
+
expect(InfluxDBRequestHandlerMock.isInfluxDBRequestHandlerMock(nil)).toEqual(false)
|
|
33
|
+
expect(InfluxDBRequestHandlerMock.isInfluxDBRequestHandlerMock({})).toEqual(false)
|
|
34
|
+
expect(InfluxDBRequestHandlerMock.isInfluxDBRequestHandlerMock(5)).toEqual(false)
|
|
35
|
+
end)
|
|
36
|
+
end)
|
|
37
|
+
|
|
38
|
+
describe("InfluxDBRequestHandlerMock.Handler", function()
|
|
39
|
+
it("should record each request in order", function()
|
|
40
|
+
local mock = InfluxDBRequestHandlerMock.new()
|
|
41
|
+
|
|
42
|
+
mock.Handler(request("https://a.example.com"))
|
|
43
|
+
mock.Handler(request("https://b.example.com"))
|
|
44
|
+
|
|
45
|
+
local requests = mock:GetRequests()
|
|
46
|
+
expect(#requests).toEqual(2)
|
|
47
|
+
expect(requests[1].Url).toEqual("https://a.example.com")
|
|
48
|
+
expect(requests[2].Url).toEqual("https://b.example.com")
|
|
49
|
+
end)
|
|
50
|
+
|
|
51
|
+
it("should resolve with a default success response", function()
|
|
52
|
+
local mock = InfluxDBRequestHandlerMock.new()
|
|
53
|
+
|
|
54
|
+
local outcome, payload = PromiseTestUtils.awaitOutcome(mock.Handler(request("https://a.example.com")))
|
|
55
|
+
expect(outcome).toEqual("resolved")
|
|
56
|
+
expect(payload.Success).toEqual(true)
|
|
57
|
+
expect(payload.StatusCode).toEqual(204)
|
|
58
|
+
end)
|
|
59
|
+
end)
|
|
60
|
+
|
|
61
|
+
describe("InfluxDBRequestHandlerMock.GetLastRequest", function()
|
|
62
|
+
it("should return nil before any request", function()
|
|
63
|
+
local mock = InfluxDBRequestHandlerMock.new()
|
|
64
|
+
expect(mock:GetLastRequest()).toEqual(nil)
|
|
65
|
+
end)
|
|
66
|
+
|
|
67
|
+
it("should return the most recent request", function()
|
|
68
|
+
local mock = InfluxDBRequestHandlerMock.new()
|
|
69
|
+
mock.Handler(request("https://a.example.com"))
|
|
70
|
+
mock.Handler(request("https://b.example.com"))
|
|
71
|
+
|
|
72
|
+
expect((mock:GetLastRequest() :: any).Url).toEqual("https://b.example.com")
|
|
73
|
+
end)
|
|
74
|
+
end)
|
|
75
|
+
|
|
76
|
+
describe("InfluxDBRequestHandlerMock.SetResponder", function()
|
|
77
|
+
it("should route requests through a custom responder", function()
|
|
78
|
+
local mock = InfluxDBRequestHandlerMock.new()
|
|
79
|
+
mock:SetResponder(function()
|
|
80
|
+
return Promise.rejected("boom")
|
|
81
|
+
end)
|
|
82
|
+
|
|
83
|
+
local outcome, payload = PromiseTestUtils.awaitOutcome(mock.Handler(request("https://a.example.com")))
|
|
84
|
+
expect(outcome).toEqual("rejected")
|
|
85
|
+
expect(payload).toEqual("boom")
|
|
86
|
+
-- The request is still recorded even when the responder rejects.
|
|
87
|
+
expect(#mock:GetRequests()).toEqual(1)
|
|
88
|
+
end)
|
|
89
|
+
|
|
90
|
+
it("should restore the default response when set back to nil", function()
|
|
91
|
+
local mock = InfluxDBRequestHandlerMock.new()
|
|
92
|
+
mock:SetResponder(function()
|
|
93
|
+
return Promise.rejected("boom")
|
|
94
|
+
end)
|
|
95
|
+
mock:SetResponder(nil)
|
|
96
|
+
|
|
97
|
+
local outcome = PromiseTestUtils.awaitOutcome(mock.Handler(request("https://a.example.com")))
|
|
98
|
+
expect(outcome).toEqual("resolved")
|
|
99
|
+
end)
|
|
100
|
+
|
|
101
|
+
it("should throw on a non-function, non-nil responder", function()
|
|
102
|
+
local mock = InfluxDBRequestHandlerMock.new()
|
|
103
|
+
expect(function()
|
|
104
|
+
mock:SetResponder(5 :: any)
|
|
105
|
+
end).toThrow("Bad responder")
|
|
106
|
+
end)
|
|
107
|
+
end)
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--[[
|
|
3
|
+
@class InfluxDBErrorUtils.spec.lua
|
|
4
|
+
]]
|
|
5
|
+
|
|
6
|
+
local require = require(script.Parent.loader).load(script)
|
|
7
|
+
|
|
8
|
+
local InfluxDBErrorUtils = require("InfluxDBErrorUtils")
|
|
9
|
+
local Jest = require("Jest")
|
|
10
|
+
|
|
11
|
+
local describe = Jest.Globals.describe
|
|
12
|
+
local expect = Jest.Globals.expect
|
|
13
|
+
local it = Jest.Globals.it
|
|
14
|
+
|
|
15
|
+
describe("InfluxDBErrorUtils.isInfluxDBError", function()
|
|
16
|
+
it("should be true for a table with string code and message", function()
|
|
17
|
+
expect(InfluxDBErrorUtils.isInfluxDBError({
|
|
18
|
+
code = "unauthorized",
|
|
19
|
+
message = "unauthorized access",
|
|
20
|
+
})).toEqual(true)
|
|
21
|
+
end)
|
|
22
|
+
|
|
23
|
+
it("should be false for a non-table", function()
|
|
24
|
+
expect(InfluxDBErrorUtils.isInfluxDBError(nil)).toEqual(false)
|
|
25
|
+
expect(InfluxDBErrorUtils.isInfluxDBError("str")).toEqual(false)
|
|
26
|
+
expect(InfluxDBErrorUtils.isInfluxDBError(5)).toEqual(false)
|
|
27
|
+
end)
|
|
28
|
+
|
|
29
|
+
it("should be false when code is missing", function()
|
|
30
|
+
expect(InfluxDBErrorUtils.isInfluxDBError({
|
|
31
|
+
message = "unauthorized access",
|
|
32
|
+
})).toEqual(false)
|
|
33
|
+
end)
|
|
34
|
+
|
|
35
|
+
it("should be false when message is not a string", function()
|
|
36
|
+
expect(InfluxDBErrorUtils.isInfluxDBError({
|
|
37
|
+
code = "unauthorized",
|
|
38
|
+
message = 5,
|
|
39
|
+
})).toEqual(false)
|
|
40
|
+
end)
|
|
41
|
+
end)
|
|
42
|
+
|
|
43
|
+
describe("InfluxDBErrorUtils.tryParseErrorBody", function()
|
|
44
|
+
it("should parse a valid InfluxDB error body", function()
|
|
45
|
+
local errorBody =
|
|
46
|
+
InfluxDBErrorUtils.tryParseErrorBody('{"code":"unauthorized","message":"unauthorized access"}')
|
|
47
|
+
|
|
48
|
+
expect(errorBody).never.toEqual(nil)
|
|
49
|
+
assert(errorBody, "no errorBody")
|
|
50
|
+
expect(errorBody.code).toEqual("unauthorized")
|
|
51
|
+
expect(errorBody.message).toEqual("unauthorized access")
|
|
52
|
+
end)
|
|
53
|
+
|
|
54
|
+
it("should return nil for a body that is not valid JSON", function()
|
|
55
|
+
expect(InfluxDBErrorUtils.tryParseErrorBody("not json")).toEqual(nil)
|
|
56
|
+
end)
|
|
57
|
+
|
|
58
|
+
it("should return nil for valid JSON that is not an InfluxDB error", function()
|
|
59
|
+
expect(InfluxDBErrorUtils.tryParseErrorBody('{"foo":"bar"}')).toEqual(nil)
|
|
60
|
+
end)
|
|
61
|
+
|
|
62
|
+
it("should return nil for a JSON array", function()
|
|
63
|
+
expect(InfluxDBErrorUtils.tryParseErrorBody("[1, 2, 3]")).toEqual(nil)
|
|
64
|
+
end)
|
|
65
|
+
|
|
66
|
+
it("should return nil for an empty string", function()
|
|
67
|
+
expect(InfluxDBErrorUtils.tryParseErrorBody("")).toEqual(nil)
|
|
68
|
+
end)
|
|
69
|
+
end)
|
|
@@ -24,6 +24,15 @@ local InfluxDBWriteAPI = setmetatable({}, BaseObject)
|
|
|
24
24
|
InfluxDBWriteAPI.ClassName = "InfluxDBWriteAPI"
|
|
25
25
|
InfluxDBWriteAPI.__index = InfluxDBWriteAPI
|
|
26
26
|
|
|
27
|
+
--[=[
|
|
28
|
+
Function used to actually send a request. Defaults to [HttpPromise.request], but can be injected so
|
|
29
|
+
tests can stand in a mock (see [InfluxDBRequestHandlerMock]) instead of making real HTTP calls.
|
|
30
|
+
|
|
31
|
+
@type InfluxDBRequestHandler (request: HttpPromise.HTTPRequest) -> Promise<HttpPromise.HTTPResponse>
|
|
32
|
+
@within InfluxDBWriteAPI
|
|
33
|
+
]=]
|
|
34
|
+
export type InfluxDBRequestHandler = (request: HttpPromise.HTTPRequest) -> Promise.Promise<HttpPromise.HTTPResponse>
|
|
35
|
+
|
|
27
36
|
export type InfluxDBWriteAPI =
|
|
28
37
|
typeof(setmetatable(
|
|
29
38
|
{} :: {
|
|
@@ -38,6 +47,7 @@ export type InfluxDBWriteAPI =
|
|
|
38
47
|
_pointSettings: InfluxDBPointSettings.InfluxDBPointSettings,
|
|
39
48
|
_writeOptions: InfluxDBWriteOptionUtils.InfluxDBWriteOptions,
|
|
40
49
|
_writeBuffer: InfluxDBWriteBuffer.InfluxDBWriteBuffer,
|
|
50
|
+
_requestHandler: InfluxDBRequestHandler,
|
|
41
51
|
},
|
|
42
52
|
{} :: typeof({ __index = InfluxDBWriteAPI })
|
|
43
53
|
))
|
|
@@ -49,14 +59,23 @@ export type InfluxDBWriteAPI =
|
|
|
49
59
|
@param org string
|
|
50
60
|
@param bucket string
|
|
51
61
|
@param precision string?
|
|
62
|
+
@param requestHandler InfluxDBRequestHandler? -- Defaults to [HttpPromise.request]. Inject a mock to avoid real HTTP.
|
|
52
63
|
@return InfluxDBWriteAPI
|
|
53
64
|
]=]
|
|
54
|
-
function InfluxDBWriteAPI.new(
|
|
65
|
+
function InfluxDBWriteAPI.new(
|
|
66
|
+
org: string,
|
|
67
|
+
bucket: string,
|
|
68
|
+
precision: string?,
|
|
69
|
+
requestHandler: InfluxDBRequestHandler?
|
|
70
|
+
): InfluxDBWriteAPI
|
|
55
71
|
local self: InfluxDBWriteAPI = setmetatable(BaseObject.new() :: any, InfluxDBWriteAPI)
|
|
56
72
|
|
|
57
73
|
assert(type(org) == "string", "Bad org")
|
|
58
74
|
assert(type(bucket) == "string", "Bad bucket")
|
|
59
75
|
assert(type(precision) == "string" or precision == nil, "Bad precision")
|
|
76
|
+
assert(type(requestHandler) == "function" or requestHandler == nil, "Bad requestHandler")
|
|
77
|
+
|
|
78
|
+
self._requestHandler = requestHandler or (HttpPromise.request :: any)
|
|
60
79
|
|
|
61
80
|
self._clientConfig = self._maid:Add(ValueObject.new(nil))
|
|
62
81
|
|
|
@@ -193,7 +212,7 @@ function InfluxDBWriteAPI._promiseSendBatch(self: InfluxDBWriteAPI, toSend: { st
|
|
|
193
212
|
end
|
|
194
213
|
|
|
195
214
|
return self._maid
|
|
196
|
-
:GivePromise(
|
|
215
|
+
:GivePromise(self._requestHandler(request))
|
|
197
216
|
:Then(function(result)
|
|
198
217
|
if result.Success then
|
|
199
218
|
if self.Destroy then
|