influxdb-client 1.2.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.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +157 -0
  3. data/.circleci/setup-rubygems.sh +3 -0
  4. data/.codecov.yml +3 -0
  5. data/.github/PULL_REQUEST_TEMPLATE +8 -0
  6. data/.gitignore +16 -0
  7. data/.rubocop.yml +38 -0
  8. data/CHANGELOG.md +27 -0
  9. data/Gemfile +24 -0
  10. data/LICENSE +21 -0
  11. data/README.md +248 -0
  12. data/Rakefile +37 -0
  13. data/bin/generate-sources.sh +23 -0
  14. data/bin/influxdb-onboarding.sh +39 -0
  15. data/bin/influxdb-restart.sh +60 -0
  16. data/bin/pom.xml +34 -0
  17. data/bin/swagger.yml +9867 -0
  18. data/influxdb-client.gemspec +53 -0
  19. data/lib/influxdb2/client.rb +29 -0
  20. data/lib/influxdb2/client/client.rb +89 -0
  21. data/lib/influxdb2/client/default_api.rb +87 -0
  22. data/lib/influxdb2/client/delete_api.rb +80 -0
  23. data/lib/influxdb2/client/flux_csv_parser.rb +251 -0
  24. data/lib/influxdb2/client/flux_table.rb +99 -0
  25. data/lib/influxdb2/client/influx_error.rb +31 -0
  26. data/lib/influxdb2/client/models/delete_predicate_request.rb +215 -0
  27. data/lib/influxdb2/client/models/dialect.rb +317 -0
  28. data/lib/influxdb2/client/models/query.rb +284 -0
  29. data/lib/influxdb2/client/point.rb +215 -0
  30. data/lib/influxdb2/client/query_api.rb +93 -0
  31. data/lib/influxdb2/client/version.rb +23 -0
  32. data/lib/influxdb2/client/worker.rb +115 -0
  33. data/lib/influxdb2/client/write_api.rb +243 -0
  34. data/test/influxdb/client_test.rb +70 -0
  35. data/test/influxdb/delete_api_integration_test.rb +100 -0
  36. data/test/influxdb/delete_api_test.rb +121 -0
  37. data/test/influxdb/flux_csv_parser_test.rb +401 -0
  38. data/test/influxdb/point_test.rb +221 -0
  39. data/test/influxdb/query_api_integration_test.rb +58 -0
  40. data/test/influxdb/query_api_stream_test.rb +98 -0
  41. data/test/influxdb/query_api_test.rb +96 -0
  42. data/test/influxdb/write_api_batching_test.rb +292 -0
  43. data/test/influxdb/write_api_integration_test.rb +76 -0
  44. data/test/influxdb/write_api_test.rb +275 -0
  45. data/test/test_helper.rb +39 -0
  46. metadata +214 -0
@@ -0,0 +1,292 @@
1
+ # The MIT License
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require 'test_helper'
22
+
23
+ class WriteApiBatchingTest < MiniTest::Test
24
+ def setup
25
+ WebMock.disable_net_connect!
26
+
27
+ @write_options = InfluxDB2::WriteOptions.new(write_type: InfluxDB2::WriteType::BATCHING,
28
+ batch_size: 2, flush_interval: 5_000, retry_interval: 2_000)
29
+ @client = InfluxDB2::Client.new('http://localhost:9999',
30
+ 'my-token',
31
+ bucket: 'my-bucket',
32
+ org: 'my-org',
33
+ precision: InfluxDB2::WritePrecision::NANOSECOND,
34
+ use_ssl: false)
35
+
36
+ @write_client = @client.create_write_api(write_options: @write_options)
37
+ end
38
+
39
+ def teardown
40
+ @client.close!
41
+
42
+ assert_equal true, @write_client.closed
43
+
44
+ WebMock.reset!
45
+ end
46
+
47
+ def test_batch_configuration
48
+ error = assert_raises ArgumentError do
49
+ InfluxDB2::WriteOptions.new(write_type: InfluxDB2::WriteType::BATCHING, batch_size: 0)
50
+ end
51
+ assert_equal "The 'batch_size' should be positive or zero, but is: 0", error.message
52
+
53
+ error = assert_raises ArgumentError do
54
+ InfluxDB2::WriteOptions.new(write_type: InfluxDB2::WriteType::BATCHING, flush_interval: -10)
55
+ end
56
+ assert_equal "The 'flush_interval' should be positive or zero, but is: -10", error.message
57
+
58
+ error = assert_raises ArgumentError do
59
+ InfluxDB2::WriteOptions.new(write_type: InfluxDB2::WriteType::BATCHING, retry_interval: 0)
60
+ end
61
+ assert_equal "The 'retry_interval' should be positive or zero, but is: 0", error.message
62
+
63
+ InfluxDB2::WriteOptions.new(write_type: InfluxDB2::WriteType::BATCHING, jitter_interval: 0)
64
+ error = assert_raises ArgumentError do
65
+ InfluxDB2::WriteOptions.new(write_type: InfluxDB2::WriteType::BATCHING, jitter_interval: -10)
66
+ end
67
+ assert_equal "The 'jitter_interval' should be positive number, but is: -10", error.message
68
+ end
69
+
70
+ def test_batch_size
71
+ stub_request(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns')
72
+ .to_return(status: 204)
73
+
74
+ @write_client.write(data: 'h2o_feet,location=coyote_creek level\\ water_level=1.0 1')
75
+ @write_client.write(data: 'h2o_feet,location=coyote_creek level\\ water_level=2.0 2')
76
+ @write_client.write(data: 'h2o_feet,location=coyote_creek level\\ water_level=3.0 3')
77
+ @write_client.write(data: 'h2o_feet,location=coyote_creek level\\ water_level=4.0 4')
78
+
79
+ sleep(1)
80
+
81
+ request1 = "h2o_feet,location=coyote_creek level\\ water_level=1.0 1\n" \
82
+ 'h2o_feet,location=coyote_creek level\\ water_level=2.0 2'
83
+ request2 = "h2o_feet,location=coyote_creek level\\ water_level=3.0 3\n" \
84
+ 'h2o_feet,location=coyote_creek level\\ water_level=4.0 4'
85
+
86
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
87
+ times: 1, body: request1)
88
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
89
+ times: 1, body: request2)
90
+ end
91
+
92
+ def test_batch_size_group_by
93
+ stub_request(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns')
94
+ .to_return(status: 204)
95
+ stub_request(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=s')
96
+ .to_return(status: 204)
97
+ stub_request(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org-a&precision=ns')
98
+ .to_return(status: 204)
99
+ stub_request(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket2&org=my-org-a&precision=ns')
100
+ .to_return(status: 204)
101
+
102
+ bucket = 'my-bucket'
103
+ bucket2 = 'my-bucket2'
104
+ org_a = 'my-org-a'
105
+
106
+ @write_client.write(data: 'h2o_feet,location=coyote_creek level\\ water_level=1.0 1', bucket: bucket, org: 'my-org')
107
+ @write_client.write(data: 'h2o_feet,location=coyote_creek level\\ water_level=2.0 2', bucket: bucket, org: 'my-org',
108
+ precision: InfluxDB2::WritePrecision::SECOND)
109
+ @write_client.write(data: 'h2o_feet,location=coyote_creek level\\ water_level=3.0 3', bucket: bucket, org: org_a)
110
+ @write_client.write(data: 'h2o_feet,location=coyote_creek level\\ water_level=4.0 4', bucket: bucket, org: org_a)
111
+ @write_client.write(data: 'h2o_feet,location=coyote_creek level\\ water_level=5.0 5', bucket: bucket2, org: org_a)
112
+ @write_client.write(data: 'h2o_feet,location=coyote_creek level\\ water_level=6.0 6', bucket: bucket, org: org_a)
113
+
114
+ sleep(1)
115
+
116
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
117
+ times: 1, body: 'h2o_feet,location=coyote_creek level\\ water_level=1.0 1')
118
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=s',
119
+ times: 1, body: 'h2o_feet,location=coyote_creek level\\ water_level=2.0 2')
120
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org-a&precision=ns',
121
+ times: 1, body: "h2o_feet,location=coyote_creek level\\ water_level=3.0 3\n" \
122
+ 'h2o_feet,location=coyote_creek level\\ water_level=4.0 4')
123
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket2&org=my-org-a&precision=ns',
124
+ times: 1, body: 'h2o_feet,location=coyote_creek level\\ water_level=5.0 5')
125
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org-a&precision=ns',
126
+ times: 1, body: 'h2o_feet,location=coyote_creek level\\ water_level=6.0 6')
127
+ end
128
+
129
+ def test_flush_interval
130
+ stub_request(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns')
131
+ .to_return(status: 204)
132
+
133
+ request1 = "h2o_feet,location=coyote_creek level\\ water_level=1.0 1\n" \
134
+ 'h2o_feet,location=coyote_creek level\\ water_level=2.0 2'
135
+ request2 = 'h2o_feet,location=coyote_creek level\\ water_level=3.0 3'
136
+
137
+ @write_client.write(data: 'h2o_feet,location=coyote_creek level\\ water_level=1.0 1')
138
+ @write_client.write(data: 'h2o_feet,location=coyote_creek level\\ water_level=2.0 2')
139
+
140
+ sleep(1)
141
+
142
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
143
+ times: 1, body: request1)
144
+
145
+ @write_client.write(data: 'h2o_feet,location=coyote_creek level\\ water_level=3.0 3')
146
+
147
+ sleep(2)
148
+
149
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
150
+ times: 0, body: request2)
151
+
152
+ sleep(3)
153
+
154
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
155
+ times: 1, body: request2)
156
+ end
157
+
158
+ def test_flush_all_by_close_client
159
+ stub_request(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns')
160
+ .to_return(status: 204)
161
+
162
+ @client.close!
163
+
164
+ @write_options = InfluxDB2::WriteOptions.new(write_type: InfluxDB2::WriteType::BATCHING,
165
+ batch_size: 10, flush_interval: 5_000)
166
+ @client = InfluxDB2::Client.new('http://localhost:9999',
167
+ 'my-token',
168
+ bucket: 'my-bucket',
169
+ org: 'my-org',
170
+ precision: InfluxDB2::WritePrecision::NANOSECOND,
171
+ use_ssl: false)
172
+
173
+ @write_client = @client.create_write_api(write_options: @write_options)
174
+
175
+ @write_client.write(data: 'h2o_feet,location=coyote_creek level\\ water_level=1.0 1')
176
+ @write_client.write(data: 'h2o_feet,location=coyote_creek level\\ water_level=2.0 2')
177
+ @write_client.write(data: 'h2o_feet,location=coyote_creek level\\ water_level=3.0 3')
178
+
179
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
180
+ times: 0, body: 'h2o_feet,location=coyote_creek level\\ water_level=3.0 3')
181
+
182
+ @client.close!
183
+
184
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
185
+ times: 1, body: "h2o_feet,location=coyote_creek level\\ water_level=1.0 1\n" \
186
+ "h2o_feet,location=coyote_creek level\\ water_level=2.0 2\n" \
187
+ 'h2o_feet,location=coyote_creek level\\ water_level=3.0 3')
188
+ end
189
+
190
+ def test_retry_interval_by_config
191
+ error_body = '{"code":"temporarily unavailable","message":"Token is temporarily over quota. '\
192
+ 'The Retry-After header describes when to try the write again."}'
193
+
194
+ stub_request(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns')
195
+ .to_return(status: 429, headers: { 'X-Platform-Error-Code' => 'temporarily unavailable' }, body: error_body).then
196
+ .to_return(status: 204)
197
+
198
+ request = "h2o_feet,location=coyote_creek water_level=1.0 1\n" \
199
+ 'h2o_feet,location=coyote_creek water_level=2.0 2'
200
+
201
+ @write_client.write(data: ['h2o_feet,location=coyote_creek water_level=1.0 1',
202
+ 'h2o_feet,location=coyote_creek water_level=2.0 2'])
203
+
204
+ sleep(0.5)
205
+
206
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
207
+ times: 1, body: request)
208
+
209
+ sleep(1)
210
+
211
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
212
+ times: 1, body: request)
213
+
214
+ sleep(1)
215
+
216
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
217
+ times: 2, body: request)
218
+ end
219
+
220
+ def test_retry_interval_by_header
221
+ error_body = '{"code":"temporarily unavailable","message":"Server is temporarily unavailable to accept writes. '\
222
+ 'The Retry-After header describes when to try the write again."}'
223
+
224
+ stub_request(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns')
225
+ .to_return(status: 503, headers: { 'X-Platform-Error-Code' => 'temporarily unavailable', 'Retry-After' => '3' },
226
+ body: error_body).then
227
+ .to_return(status: 204)
228
+
229
+ request = "h2o_feet,location=coyote_creek water_level=1.0 1\n" \
230
+ 'h2o_feet,location=coyote_creek water_level=2.0 2'
231
+
232
+ @write_client.write(data: ['h2o_feet,location=coyote_creek water_level=1.0 1',
233
+ InfluxDB2::Point.new(name: 'h2o_feet')
234
+ .add_tag('location', 'coyote_creek')
235
+ .add_field('water_level', 2.0)
236
+ .time(2, InfluxDB2::WritePrecision::NANOSECOND)])
237
+
238
+ sleep(0.5)
239
+
240
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
241
+ times: 1, body: request)
242
+
243
+ sleep(1)
244
+
245
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
246
+ times: 1, body: request)
247
+
248
+ sleep(1)
249
+
250
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
251
+ times: 1, body: request)
252
+
253
+ sleep(1)
254
+
255
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
256
+ times: 2, body: request)
257
+ end
258
+
259
+ def test_jitter_interval
260
+ @client.close!
261
+
262
+ @client = InfluxDB2::Client.new('http://localhost:9999',
263
+ 'my-token',
264
+ bucket: 'my-bucket',
265
+ org: 'my-org',
266
+ precision: InfluxDB2::WritePrecision::NANOSECOND,
267
+ use_ssl: false)
268
+
269
+ @write_options = InfluxDB2::WriteOptions.new(write_type: InfluxDB2::WriteType::BATCHING,
270
+ batch_size: 2, flush_interval: 5_000, jitter_interval: 2_000)
271
+ @write_client = @client.create_write_api(write_options: @write_options)
272
+
273
+ stub_request(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns')
274
+ .to_return(status: 204)
275
+
276
+ request = "h2o_feet,location=coyote_creek water_level=1.0 1\n" \
277
+ 'h2o_feet,location=coyote_creek water_level=2.0 2'
278
+
279
+ @write_client.write(data: ['h2o_feet,location=coyote_creek water_level=1.0 1',
280
+ 'h2o_feet,location=coyote_creek water_level=2.0 2'])
281
+
282
+ sleep(0.05)
283
+
284
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
285
+ times: 0, body: request)
286
+
287
+ sleep(2)
288
+
289
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
290
+ times: 1, body: request)
291
+ end
292
+ end
@@ -0,0 +1,76 @@
1
+ # The MIT License
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require 'test_helper'
22
+ require 'csv'
23
+
24
+ class WriteApiIntegrationTest < MiniTest::Test
25
+ def setup
26
+ WebMock.allow_net_connect!
27
+ end
28
+
29
+ def test_write_into_influx_db
30
+ client = InfluxDB2::Client.new('http://localhost:9999', 'my-token',
31
+ bucket: 'my-bucket',
32
+ org: 'my-org',
33
+ precision: InfluxDB2::WritePrecision::NANOSECOND,
34
+ use_ssl: false)
35
+
36
+ now = Time.now.utc
37
+
38
+ measurement = 'h2o_' + now.to_i.to_s + now.nsec.to_s
39
+ point = InfluxDB2::Point.new(name: measurement)
40
+ .add_tag('location', 'europe')
41
+ .add_field('level', 2)
42
+ .time(now, InfluxDB2::WritePrecision::NANOSECOND)
43
+
44
+ client.create_write_api.write(data: point)
45
+
46
+ csv = _query(measurement)
47
+
48
+ refute_nil csv
49
+ assert_equal measurement, csv[0]['_measurement']
50
+ assert_equal 'europe', csv[0]['location']
51
+ assert_equal '2', csv[0]['_value']
52
+ assert_equal 'level', csv[0]['_field']
53
+ end
54
+
55
+ private
56
+
57
+ def _query(measurement)
58
+ query = { 'query': 'from(bucket: "my-bucket") |> range(start: -15m, stop: now()) '\
59
+ "|> filter(fn: (r) => r._measurement == \"#{measurement}\")", 'type': 'flux' }
60
+
61
+ uri = URI.parse('http://localhost:9999/api/v2/query?org=my-org')
62
+ request = Net::HTTP::Post.new(uri.request_uri)
63
+ request['Authorization'] = 'Token my-token'
64
+ request[InfluxDB2::DefaultApi::HEADER_CONTENT_TYPE] = 'application/json'
65
+ request.body = query.to_json
66
+
67
+ http = Net::HTTP.new(uri.host, uri.port)
68
+ begin
69
+ response = http.request(request)
70
+
71
+ CSV.parse(response.body, headers: true)
72
+ ensure
73
+ http.finish if http.started?
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,275 @@
1
+ # The MIT License
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require 'test_helper'
22
+
23
+ class WriteApiTest < MiniTest::Test
24
+ def setup
25
+ WebMock.disable_net_connect!
26
+ end
27
+
28
+ def test_required_arguments
29
+ client = InfluxDB2::Client.new('http://localhost:9999', 'my-token')
30
+ write_api = client.create_write_api
31
+
32
+ # precision
33
+ assert_raises ArgumentError do
34
+ write_api.write(data: {}, bucket: 'my-bucket', org: 'my-org')
35
+ end
36
+ # bucket
37
+ assert_raises ArgumentError do
38
+ write_api.write(data: {}, org: 'my-org', precision: InfluxDB2::WritePrecision::NANOSECOND)
39
+ end
40
+ # org
41
+ assert_raises ArgumentError do
42
+ write_api.write(data: {}, bucket: 'my-bucket', precision: InfluxDB2::WritePrecision::NANOSECOND)
43
+ end
44
+ end
45
+
46
+ def test_default_arguments_
47
+ client = InfluxDB2::Client.new('http://localhost:9999', 'my-token',
48
+ bucket: 'my-bucket',
49
+ org: 'my-org',
50
+ precision: InfluxDB2::WritePrecision::NANOSECOND)
51
+ write_api = client.create_write_api
52
+
53
+ # without argument errors
54
+ write_api.write(data: {})
55
+ end
56
+
57
+ def test_write_line_protocol
58
+ stub_request(:any, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns')
59
+ .to_return(status: 204)
60
+ client = InfluxDB2::Client.new('http://localhost:9999', 'my-token',
61
+ bucket: 'my-bucket',
62
+ org: 'my-org',
63
+ precision: InfluxDB2::WritePrecision::NANOSECOND,
64
+ use_ssl: false)
65
+
66
+ client.create_write_api.write(data: 'h2o,location=west value=33i 15')
67
+
68
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
69
+ times: 1, body: 'h2o,location=west value=33i 15')
70
+ end
71
+
72
+ def test_write_point
73
+ stub_request(:any, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns')
74
+ .to_return(status: 204)
75
+ client = InfluxDB2::Client.new('http://localhost:9999', 'my-token',
76
+ bucket: 'my-bucket',
77
+ org: 'my-org',
78
+ precision: InfluxDB2::WritePrecision::NANOSECOND,
79
+ use_ssl: false)
80
+
81
+ client.create_write_api.write(data: InfluxDB2::Point.new(name: 'h2o')
82
+ .add_tag('location', 'europe')
83
+ .add_field('level', 2))
84
+
85
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
86
+ times: 1, body: 'h2o,location=europe level=2i')
87
+ end
88
+
89
+ def test_write_hash
90
+ stub_request(:any, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns')
91
+ .to_return(status: 204)
92
+ client = InfluxDB2::Client.new('http://localhost:9999', 'my-token',
93
+ bucket: 'my-bucket',
94
+ org: 'my-org',
95
+ precision: InfluxDB2::WritePrecision::NANOSECOND,
96
+ use_ssl: false)
97
+
98
+ client.create_write_api.write(data: { name: 'h2o',
99
+ tags: { host: 'aws', region: 'us' },
100
+ fields: { level: 5, saturation: '99%' }, time: 123 })
101
+
102
+ expected = 'h2o,host=aws,region=us level=5i,saturation="99%" 123'
103
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
104
+ times: 1, body: expected)
105
+ end
106
+
107
+ def test_write_collection
108
+ stub_request(:any, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns')
109
+ .to_return(status: 204)
110
+ client = InfluxDB2::Client.new('http://localhost:9999', 'my-token',
111
+ bucket: 'my-bucket',
112
+ org: 'my-org',
113
+ precision: InfluxDB2::WritePrecision::NANOSECOND,
114
+ use_ssl: false)
115
+
116
+ point = InfluxDB2::Point.new(name: 'h2o')
117
+ .add_tag('location', 'europe')
118
+ .add_field('level', 2)
119
+
120
+ hash = { name: 'h2o',
121
+ tags: { host: 'aws', region: 'us' },
122
+ fields: { level: 5, saturation: '99%' }, time: 123 }
123
+
124
+ client.create_write_api.write(data: ['h2o,location=west value=33i 15', nil, '', point, hash])
125
+
126
+ expected = "h2o,location=west value=33i 15\nh2o,location=europe level=2i"\
127
+ "\nh2o,host=aws,region=us level=5i,saturation=\"99%\" 123"
128
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
129
+ times: 1, body: expected)
130
+ end
131
+
132
+ def test_array_of_array
133
+ stub_request(:any, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns')
134
+ .to_return(status: 204)
135
+ client = InfluxDB2::Client.new('http://localhost:9999', 'my-token',
136
+ bucket: 'my-bucket',
137
+ org: 'my-org',
138
+ precision: InfluxDB2::WritePrecision::NANOSECOND,
139
+ use_ssl: false)
140
+
141
+ client.create_write_api.write(data: ['h2o,location=west value=33i 15', ['h2o,location=west value=34i 16',
142
+ 'h2o,location=west value=35i 17']])
143
+
144
+ expected = "h2o,location=west value=33i 15\nh2o,location=west value=34i 16"\
145
+ "\nh2o,location=west value=35i 17"
146
+
147
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
148
+ times: 1, body: expected)
149
+ end
150
+
151
+ def test_authorization_header
152
+ stub_request(:any, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns')
153
+ .to_return(status: 204)
154
+ client = InfluxDB2::Client.new('http://localhost:9999', 'my-token',
155
+ bucket: 'my-bucket',
156
+ org: 'my-org',
157
+ precision: InfluxDB2::WritePrecision::NANOSECOND,
158
+ use_ssl: false)
159
+
160
+ client.create_write_api.write(data: 'h2o,location=west value=33i 15')
161
+
162
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
163
+ times: 1, headers: { 'Authorization' => 'Token my-token' })
164
+ end
165
+
166
+ def test_without_data
167
+ stub_request(:any, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns')
168
+ .to_return(status: 204)
169
+ client = InfluxDB2::Client.new('http://localhost:9999', 'my-token',
170
+ bucket: 'my-bucket',
171
+ org: 'my-org',
172
+ precision: InfluxDB2::WritePrecision::NANOSECOND)
173
+
174
+ client.create_write_api.write(data: '')
175
+
176
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns', times: 0)
177
+ end
178
+
179
+ def test_influx_exception
180
+ error_body = '{"code":"invalid","message":"unable to parse '\
181
+ '\'h2o_feet, location=coyote_creek water_level=1.0 1\': missing tag key"}'
182
+
183
+ stub_request(:any, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns')
184
+ .to_return(status: 400, headers: { 'X-Platform-Error-Code' => 'invalid' }, body: error_body)
185
+
186
+ client = InfluxDB2::Client.new('http://localhost:9999', 'my-token',
187
+ bucket: 'my-bucket',
188
+ org: 'my-org',
189
+ precision: InfluxDB2::WritePrecision::NANOSECOND,
190
+ use_ssl: false)
191
+
192
+ error = assert_raises InfluxDB2::InfluxError do
193
+ client.create_write_api.write(data: 'h2o,location=west value=33i 15')
194
+ end
195
+
196
+ assert_equal '400', error.code
197
+ assert_equal 'invalid', error.reference
198
+ assert_equal "unable to parse 'h2o_feet, location=coyote_creek water_level=1.0 1': missing tag key", error.message
199
+ end
200
+
201
+ def test_follow_redirect
202
+ stub_request(:any, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns')
203
+ .to_return(status: 307, headers:
204
+ { 'location' => 'http://localhost:9090/api/v2/write?bucket=my-bucket&org=my-org&precision=ns' })
205
+ .then.to_return(status: 204)
206
+ stub_request(:any, 'http://localhost:9090/api/v2/write?bucket=my-bucket&org=my-org&precision=ns')
207
+ .to_return(status: 204)
208
+
209
+ client = InfluxDB2::Client.new('http://localhost:9999', 'my-token',
210
+ bucket: 'my-bucket',
211
+ org: 'my-org',
212
+ precision: InfluxDB2::WritePrecision::NANOSECOND,
213
+ use_ssl: false)
214
+
215
+ client.create_write_api.write(data: 'h2o,location=west value=33i 15')
216
+
217
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
218
+ times: 1, body: 'h2o,location=west value=33i 15')
219
+ assert_requested(:post, 'http://localhost:9090/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
220
+ times: 1, body: 'h2o,location=west value=33i 15')
221
+ end
222
+
223
+ def test_follow_redirect_max
224
+ stub_request(:any, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns')
225
+ .to_return(status: 307, headers:
226
+ { 'location' => 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns' })
227
+
228
+ client = InfluxDB2::Client.new('http://localhost:9999', 'my-token',
229
+ bucket: 'my-bucket',
230
+ org: 'my-org',
231
+ precision: InfluxDB2::WritePrecision::NANOSECOND,
232
+ max_redirect_count: 5,
233
+ use_ssl: false)
234
+
235
+ error = assert_raises InfluxDB2::InfluxError do
236
+ client.create_write_api.write(data: 'h2o,location=west value=33i 15')
237
+ end
238
+
239
+ assert_equal 'Too many HTTP redirects. Exceeded limit: 5', error.message
240
+ end
241
+
242
+ def test_write_precision_constant
243
+ assert_equal InfluxDB2::WritePrecision::SECOND, InfluxDB2::WritePrecision.new.get_from_value('s')
244
+ assert_equal InfluxDB2::WritePrecision::MILLISECOND, InfluxDB2::WritePrecision.new.get_from_value('ms')
245
+ assert_equal InfluxDB2::WritePrecision::MICROSECOND, InfluxDB2::WritePrecision.new.get_from_value('us')
246
+ assert_equal InfluxDB2::WritePrecision::NANOSECOND, InfluxDB2::WritePrecision.new.get_from_value('ns')
247
+
248
+ error = assert_raises RuntimeError do
249
+ InfluxDB2::WritePrecision.new.get_from_value('not_supported')
250
+ end
251
+
252
+ assert_equal 'The time precision not_supported is not supported.', error.message
253
+ end
254
+
255
+ def test_headers
256
+ stub_request(:any, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns')
257
+ .to_return(status: 204)
258
+
259
+ client = InfluxDB2::Client.new('http://localhost:9999', 'my-token',
260
+ bucket: 'my-bucket',
261
+ org: 'my-org',
262
+ precision: InfluxDB2::WritePrecision::NANOSECOND,
263
+ use_ssl: false)
264
+
265
+ client.create_write_api.write(data: 'h2o,location=west value=33i 15')
266
+
267
+ headers = {
268
+ 'Authorization' => 'Token my-token',
269
+ 'User-Agent' => "influxdb-client-ruby/#{InfluxDB2::VERSION}",
270
+ 'Content-Type' => 'text/plain'
271
+ }
272
+ assert_requested(:post, 'http://localhost:9999/api/v2/write?bucket=my-bucket&org=my-org&precision=ns',
273
+ times: 1, body: 'h2o,location=west value=33i 15', headers: headers)
274
+ end
275
+ end