influxdb-client 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/PULL_REQUEST_TEMPLATE +4 -4
- data/.rubocop.yml +2 -2
- data/CHANGELOG.md +15 -0
- data/README.md +26 -4
- data/bin/generate-sources.sh +1 -8
- data/influxdb-client.gemspec +1 -1
- data/lib/influxdb2/client.rb +1 -0
- data/lib/influxdb2/client/client.rb +7 -0
- data/lib/influxdb2/client/default_api.rb +21 -2
- data/lib/influxdb2/client/delete_api.rb +80 -0
- data/lib/influxdb2/client/flux_csv_parser.rb +7 -2
- data/lib/influxdb2/client/influx_error.rb +7 -3
- data/lib/influxdb2/client/models/delete_predicate_request.rb +215 -0
- data/lib/influxdb2/client/query_api.rb +1 -1
- data/lib/influxdb2/client/version.rb +1 -1
- data/lib/influxdb2/client/worker.rb +39 -13
- data/lib/influxdb2/client/write_api.rb +32 -8
- data/test/influxdb/delete_api_integration_test.rb +100 -0
- data/test/influxdb/delete_api_test.rb +121 -0
- data/test/influxdb/flux_csv_parser_test.rb +75 -0
- data/test/influxdb/query_api_integration_test.rb +1 -1
- data/test/influxdb/query_api_test.rb +21 -0
- data/test/influxdb/write_api_batching_test.rb +140 -1
- data/test/influxdb/write_api_integration_test.rb +2 -1
- data/test/influxdb/write_api_test.rb +40 -0
- metadata +12 -6
@@ -73,7 +73,7 @@ module InfluxDB2
|
|
73
73
|
uri = URI.parse(File.join(@options[:url], '/api/v2/query'))
|
74
74
|
uri.query = URI.encode_www_form(org: org_param)
|
75
75
|
|
76
|
-
|
76
|
+
_post_json(payload.to_body.to_json, uri)
|
77
77
|
end
|
78
78
|
|
79
79
|
def _generate_payload(query, dialect)
|
@@ -33,24 +33,36 @@ module InfluxDB2
|
|
33
33
|
|
34
34
|
@thread_flush = Thread.new do
|
35
35
|
until api_client.closed
|
36
|
-
sleep @write_options.flush_interval / 1_000
|
37
|
-
|
36
|
+
sleep @write_options.flush_interval.to_f / 1_000
|
37
|
+
_check_background_queue
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
41
|
@thread_size = Thread.new do
|
42
42
|
until api_client.closed
|
43
|
-
|
43
|
+
_check_background_queue(size: true) if @queue.length >= @write_options.batch_size
|
44
44
|
sleep 0.01
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
49
|
def push(payload)
|
50
|
-
|
50
|
+
if payload.respond_to? :each
|
51
|
+
payload.each do |item|
|
52
|
+
push(item)
|
53
|
+
end
|
54
|
+
else
|
55
|
+
@queue.push(payload)
|
56
|
+
end
|
51
57
|
end
|
52
58
|
|
53
|
-
def
|
59
|
+
def flush_all
|
60
|
+
_check_background_queue until @queue.empty?
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def _check_background_queue(size: false)
|
54
66
|
@queue_event.pop
|
55
67
|
data = {}
|
56
68
|
points = 0
|
@@ -60,7 +72,7 @@ module InfluxDB2
|
|
60
72
|
return
|
61
73
|
end
|
62
74
|
|
63
|
-
while (
|
75
|
+
while (points < @write_options.batch_size) && !@queue.empty?
|
64
76
|
begin
|
65
77
|
item = @queue.pop(true)
|
66
78
|
key = item.key
|
@@ -68,22 +80,36 @@ module InfluxDB2
|
|
68
80
|
data[key] << item.data
|
69
81
|
points += 1
|
70
82
|
rescue ThreadError
|
83
|
+
@queue_event.push(true)
|
71
84
|
return
|
72
85
|
end
|
73
86
|
end
|
74
87
|
|
75
|
-
|
76
|
-
|
88
|
+
begin
|
89
|
+
_write(data) unless data.values.flatten.empty?
|
90
|
+
ensure
|
91
|
+
@queue_event.push(true)
|
92
|
+
end
|
77
93
|
end
|
78
94
|
|
79
|
-
def
|
80
|
-
|
95
|
+
def _write(data)
|
96
|
+
data.each do |key, points|
|
97
|
+
_write_raw(key, points)
|
98
|
+
end
|
81
99
|
end
|
82
100
|
|
83
|
-
def
|
84
|
-
|
85
|
-
@
|
101
|
+
def _write_raw(key, points)
|
102
|
+
if @write_options.jitter_interval.positive?
|
103
|
+
jitter_delay = (@write_options.jitter_interval.to_f / 1_000) * rand
|
104
|
+
sleep jitter_delay
|
86
105
|
end
|
106
|
+
@api_client.write_raw(points.join("\n"), precision: key.precision, bucket: key.bucket, org: key.org)
|
107
|
+
rescue InfluxError => e
|
108
|
+
raise e if e.code.nil? || !(%w[429 503].include? e.code)
|
109
|
+
|
110
|
+
timeout = e.retry_after.empty? ? @write_options.retry_interval.to_f / 1_000 : e.retry_after.to_f
|
111
|
+
sleep timeout
|
112
|
+
_write_raw(key, points)
|
87
113
|
end
|
88
114
|
end
|
89
115
|
end
|
@@ -27,17 +27,36 @@ module InfluxDB2
|
|
27
27
|
|
28
28
|
# Creates write api configuration.
|
29
29
|
#
|
30
|
-
# @param write_type: methods of write (batching, asynchronous, synchronous)
|
31
|
-
# @param batch_size: the number of data point to collect in batch
|
32
|
-
# @param flush_interval: flush data at least in this interval
|
33
30
|
class WriteOptions
|
34
|
-
|
31
|
+
# @param [WriteType] write_type: methods of write (batching, synchronous)
|
32
|
+
# @param [Integer] batch_size: the number of data point to collect in batch
|
33
|
+
# @param [Integer] flush_interval: flush data at least in this interval
|
34
|
+
# @param [Integer] retry_interval: number of milliseconds to retry unsuccessful write.
|
35
|
+
# The retry interval is used when the InfluxDB server does not specify "Retry-After" header.
|
36
|
+
# @param [Integer] jitter_interval: the number of milliseconds to increase the batch flush interval
|
37
|
+
# by a random amount
|
38
|
+
def initialize(write_type: WriteType::SYNCHRONOUS, batch_size: 1_000, flush_interval: 1_000, retry_interval: 1_000,
|
39
|
+
jitter_interval: 0)
|
40
|
+
_check_not_negative('batch_size', batch_size)
|
41
|
+
_check_not_negative('flush_interval', flush_interval)
|
42
|
+
_check_not_negative('retry_interval', retry_interval)
|
43
|
+
_check_positive('jitter_interval', jitter_interval)
|
35
44
|
@write_type = write_type
|
36
45
|
@batch_size = batch_size
|
37
46
|
@flush_interval = flush_interval
|
47
|
+
@retry_interval = retry_interval
|
48
|
+
@jitter_interval = jitter_interval
|
38
49
|
end
|
39
50
|
|
40
|
-
attr_reader :write_type, :batch_size, :flush_interval
|
51
|
+
attr_reader :write_type, :batch_size, :flush_interval, :retry_interval, :jitter_interval
|
52
|
+
|
53
|
+
def _check_not_negative(key, value)
|
54
|
+
raise ArgumentError, "The '#{key}' should be positive or zero, but is: #{value}" if value <= 0
|
55
|
+
end
|
56
|
+
|
57
|
+
def _check_positive(key, value)
|
58
|
+
raise ArgumentError, "The '#{key}' should be positive number, but is: #{value}" if value < 0
|
59
|
+
end
|
41
60
|
end
|
42
61
|
|
43
62
|
SYNCHRONOUS = InfluxDB2::WriteOptions.new(write_type: WriteType::SYNCHRONOUS)
|
@@ -144,7 +163,7 @@ module InfluxDB2
|
|
144
163
|
uri = URI.parse(File.join(@options[:url], '/api/v2/write'))
|
145
164
|
uri.query = URI.encode_www_form(bucket: bucket_param, org: org_param, precision: precision_param.to_s)
|
146
165
|
|
147
|
-
|
166
|
+
_post_text(payload, uri)
|
148
167
|
end
|
149
168
|
|
150
169
|
# Item for batching queue
|
@@ -210,9 +229,14 @@ module InfluxDB2
|
|
210
229
|
elsif data.is_a?(Hash)
|
211
230
|
_generate_payload(Point.from_hash(data), bucket: bucket, org: org, precision: precision)
|
212
231
|
elsif data.respond_to? :map
|
213
|
-
data.map do |item|
|
232
|
+
payloads = data.map do |item|
|
214
233
|
_generate_payload(item, bucket: bucket, org: org, precision: precision)
|
215
|
-
end.reject(&:nil?)
|
234
|
+
end.reject(&:nil?)
|
235
|
+
if @write_options.write_type == WriteType::BATCHING
|
236
|
+
payloads
|
237
|
+
else
|
238
|
+
payloads.join("\n".freeze)
|
239
|
+
end
|
216
240
|
end
|
217
241
|
end
|
218
242
|
end
|
@@ -0,0 +1,100 @@
|
|
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 DeleteApiIntegrationTest < MiniTest::Test
|
24
|
+
def setup
|
25
|
+
WebMock.allow_net_connect!
|
26
|
+
|
27
|
+
@client = InfluxDB2::Client.new('http://localhost:9999', 'my-token',
|
28
|
+
bucket: 'my-bucket',
|
29
|
+
org: 'my-org',
|
30
|
+
precision: InfluxDB2::WritePrecision::NANOSECOND,
|
31
|
+
use_ssl: false)
|
32
|
+
|
33
|
+
now = Time.now.utc
|
34
|
+
@measurement = 'h2o_delete_' + now.to_i.to_s + +now.nsec.to_s
|
35
|
+
|
36
|
+
data = [InfluxDB2::Point.new(name: @measurement)
|
37
|
+
.add_tag('location', 'europe')
|
38
|
+
.add_field('level', 2)
|
39
|
+
.time(Time.utc(2015, 10, 15, 8, 20, 15), InfluxDB2::WritePrecision::MILLISECOND),
|
40
|
+
InfluxDB2::Point.new(name: @measurement)
|
41
|
+
.add_tag('location', 'us')
|
42
|
+
.add_field('level', 2)
|
43
|
+
.time(Time.utc(2016, 10, 15, 8, 20, 15), InfluxDB2::WritePrecision::MILLISECOND),
|
44
|
+
InfluxDB2::Point.new(name: @measurement)
|
45
|
+
.add_tag('location', 'india')
|
46
|
+
.add_field('level', 2)
|
47
|
+
.time(Time.utc(2017, 10, 15, 8, 20, 15), InfluxDB2::WritePrecision::MILLISECOND),
|
48
|
+
InfluxDB2::Point.new(name: @measurement)
|
49
|
+
.add_tag('location', 'europe')
|
50
|
+
.add_field('level', 2)
|
51
|
+
.time(Time.utc(2018, 10, 15, 8, 20, 15), InfluxDB2::WritePrecision::MILLISECOND)]
|
52
|
+
|
53
|
+
@client.create_write_api.write(data: data, precision: InfluxDB2::WritePrecision::MILLISECOND)
|
54
|
+
|
55
|
+
assert_equal 4, _query_count
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_delete
|
59
|
+
@client.create_delete_api.delete(Time.utc(2015, 10, 16, 8, 20, 15), Time.utc(2020, 10, 16, 8, 20, 15),
|
60
|
+
predicate: 'location="europe"')
|
61
|
+
|
62
|
+
assert_equal 3, _query_count
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_delete_without_predicate
|
66
|
+
@client.create_delete_api.delete(Time.utc(2016, 10, 15, 7, 20, 15), Time.utc(2018, 10, 14, 8, 20, 15))
|
67
|
+
|
68
|
+
assert_equal 2, _query_count
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_delete_all
|
72
|
+
@client.create_delete_api.delete(Time.utc(2010, 10, 15, 7, 20, 15), Time.utc(2020, 10, 14, 8, 20, 15))
|
73
|
+
|
74
|
+
assert_equal 0, _query_count
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_delete_without_interval
|
78
|
+
error = assert_raises InfluxDB2::InfluxError do
|
79
|
+
@client.create_delete_api.delete(nil, nil)
|
80
|
+
end
|
81
|
+
|
82
|
+
assert error.message.include?('invalid request'),
|
83
|
+
"Error message: '#{error.message}' doesn't contains 'invalid request'"
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def _query_count
|
89
|
+
query = 'from(bucket: "my-bucket") |> range(start: 0) |> ' \
|
90
|
+
"filter(fn: (r) => r._measurement == \"#{@measurement}\") " \
|
91
|
+
'|> drop(columns: ["location"]) |> count()'
|
92
|
+
|
93
|
+
table = @client.create_query_api.query(query: InfluxDB2::Query.new(query: query,
|
94
|
+
dialect: InfluxDB2::QueryApi::DEFAULT_DIALECT,
|
95
|
+
type: nil))[0]
|
96
|
+
return 0 if table.nil?
|
97
|
+
|
98
|
+
table.records[0].value
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,121 @@
|
|
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 DeleteApiTest < MiniTest::Test
|
24
|
+
def setup
|
25
|
+
WebMock.disable_net_connect!
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_delete
|
29
|
+
stub_request(:any, 'http://localhost:9999/api/v2/delete?bucket=my-bucket&org=my-org')
|
30
|
+
.to_return(status: 204)
|
31
|
+
client = InfluxDB2::Client.new('http://localhost:9999', 'my-token',
|
32
|
+
bucket: 'my-bucket',
|
33
|
+
org: 'my-org',
|
34
|
+
precision: InfluxDB2::WritePrecision::NANOSECOND,
|
35
|
+
use_ssl: false)
|
36
|
+
|
37
|
+
client.create_delete_api.delete(Time.utc(2019, 10, 15, 8, 20, 15), Time.utc(2019, 11, 15, 8, 20, 15),
|
38
|
+
predicate: 'key1="value1" AND key2="value"', bucket: 'my-bucket', org: 'my-org')
|
39
|
+
|
40
|
+
body = '{"start":"2019-10-15T08:20:15+00:00","stop":"2019-11-15T08:20:15+00:00","predicate":"key1=\"value1\" ' \
|
41
|
+
'AND key2=\"value\""}'
|
42
|
+
|
43
|
+
assert_requested(:post, 'http://localhost:9999/api/v2/delete?bucket=my-bucket&org=my-org', times: 1, body: body)
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_delete_time_as_date_time
|
47
|
+
stub_request(:any, 'http://localhost:9999/api/v2/delete?bucket=my-bucket&org=my-org')
|
48
|
+
.to_return(status: 204)
|
49
|
+
client = InfluxDB2::Client.new('http://localhost:9999', 'my-token',
|
50
|
+
bucket: 'my-bucket',
|
51
|
+
org: 'my-org',
|
52
|
+
precision: InfluxDB2::WritePrecision::NANOSECOND,
|
53
|
+
use_ssl: false)
|
54
|
+
|
55
|
+
client.create_delete_api.delete(DateTime.rfc3339('2019-02-03T04:05:06+07:00'),
|
56
|
+
DateTime.rfc3339('2019-03-03T04:05:06+07:00'),
|
57
|
+
predicate: 'key1="value1" AND key2="value"', bucket: 'my-bucket', org: 'my-org')
|
58
|
+
|
59
|
+
body = '{"start":"2019-02-03T04:05:06+07:00","stop":"2019-03-03T04:05:06+07:00","predicate":"key1=\"value1\" ' \
|
60
|
+
'AND key2=\"value\""}'
|
61
|
+
|
62
|
+
assert_requested(:post, 'http://localhost:9999/api/v2/delete?bucket=my-bucket&org=my-org', times: 1, body: body)
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_delete_time_as_string
|
66
|
+
stub_request(:any, 'http://localhost:9999/api/v2/delete?bucket=my-bucket&org=my-org')
|
67
|
+
.to_return(status: 204)
|
68
|
+
client = InfluxDB2::Client.new('http://localhost:9999', 'my-token',
|
69
|
+
bucket: 'my-bucket',
|
70
|
+
org: 'my-org',
|
71
|
+
precision: InfluxDB2::WritePrecision::NANOSECOND,
|
72
|
+
use_ssl: false)
|
73
|
+
|
74
|
+
client.create_delete_api.delete('2019-02-03T04:05:06+07:00', '2019-04-03T04:05:06+07:00',
|
75
|
+
predicate: 'key1="value1" AND key2="value"', bucket: 'my-bucket', org: 'my-org')
|
76
|
+
|
77
|
+
body = '{"start":"2019-02-03T04:05:06+07:00","stop":"2019-04-03T04:05:06+07:00","predicate":"key1=\"value1\" ' \
|
78
|
+
'AND key2=\"value\""}'
|
79
|
+
|
80
|
+
assert_requested(:post, 'http://localhost:9999/api/v2/delete?bucket=my-bucket&org=my-org', times: 1, body: body)
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_without_predicate
|
84
|
+
stub_request(:any, 'http://localhost:9999/api/v2/delete?bucket=my-bucket&org=my-org')
|
85
|
+
.to_return(status: 204)
|
86
|
+
client = InfluxDB2::Client.new('http://localhost:9999', 'my-token',
|
87
|
+
bucket: 'my-bucket',
|
88
|
+
org: 'my-org',
|
89
|
+
precision: InfluxDB2::WritePrecision::NANOSECOND,
|
90
|
+
use_ssl: false)
|
91
|
+
|
92
|
+
client.create_delete_api.delete('2019-02-03T04:05:06+07:00', '2019-04-03T04:05:06+07:00',
|
93
|
+
bucket: 'my-bucket', org: 'my-org')
|
94
|
+
|
95
|
+
body = '{"start":"2019-02-03T04:05:06+07:00","stop":"2019-04-03T04:05:06+07:00"}'
|
96
|
+
|
97
|
+
assert_requested(:post, 'http://localhost:9999/api/v2/delete?bucket=my-bucket&org=my-org', times: 1, body: body)
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_user_agent_header
|
101
|
+
stub_request(:any, 'http://localhost:9999/api/v2/delete?bucket=my-bucket&org=my-org')
|
102
|
+
.to_return(status: 204)
|
103
|
+
client = InfluxDB2::Client.new('http://localhost:9999', 'my-token',
|
104
|
+
bucket: 'my-bucket',
|
105
|
+
org: 'my-org',
|
106
|
+
precision: InfluxDB2::WritePrecision::NANOSECOND,
|
107
|
+
use_ssl: false)
|
108
|
+
|
109
|
+
client.create_delete_api.delete('2019-02-03T04:05:06+07:00', '2019-04-03T04:05:06+07:00',
|
110
|
+
bucket: 'my-bucket', org: 'my-org')
|
111
|
+
|
112
|
+
body = '{"start":"2019-02-03T04:05:06+07:00","stop":"2019-04-03T04:05:06+07:00"}'
|
113
|
+
headers = {
|
114
|
+
'Authorization' => 'Token my-token',
|
115
|
+
'User-Agent' => "influxdb-client-ruby/#{InfluxDB2::VERSION}",
|
116
|
+
'Content-Type' => 'application/json'
|
117
|
+
}
|
118
|
+
assert_requested(:post, 'http://localhost:9999/api/v2/delete?bucket=my-bucket&org=my-org',
|
119
|
+
times: 1, body: body, headers: headers)
|
120
|
+
end
|
121
|
+
end
|
@@ -323,4 +323,79 @@ class FluxCsvParserErrorTest < MiniTest::Test
|
|
323
323
|
|
324
324
|
assert_equal 'Unable to parse CSV response. FluxTable definition was not found.', error.message
|
325
325
|
end
|
326
|
+
|
327
|
+
def test_multiple_queries
|
328
|
+
data = "#datatype,string,long,string,string,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,double,string\n" \
|
329
|
+
"#group,false,false,true,true,true,true,false,false,true\n" \
|
330
|
+
"#default,t1,,,,,,,,\n" \
|
331
|
+
",result,table,_field,_measurement,_start,_stop,_time,_value,tag\n" \
|
332
|
+
",,0,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:20:00Z,2,test1\n" \
|
333
|
+
",,0,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:21:40Z,2,test1\n" \
|
334
|
+
",,0,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:23:20Z,2,test1\n" \
|
335
|
+
",,0,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:25:00Z,2,test1\n" \
|
336
|
+
",,0,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:26:40Z,2,test1\n" \
|
337
|
+
",,0,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:28:20Z,2,test1\n" \
|
338
|
+
",,0,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:30:00Z,2,test1\n" \
|
339
|
+
",,1,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:20:00Z,2,test2\n" \
|
340
|
+
",,1,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:21:40Z,2,test2\n" \
|
341
|
+
",,1,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:23:20Z,2,test2\n" \
|
342
|
+
",,1,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:25:00Z,2,test2\n" \
|
343
|
+
",,1,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:26:40Z,2,test2\n" \
|
344
|
+
",,1,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:28:20Z,2,test2\n" \
|
345
|
+
",,1,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:30:00Z,2,test2\n" \
|
346
|
+
"\n" \
|
347
|
+
"#datatype,string,long,string,string,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,double,string\n" \
|
348
|
+
"#group,false,false,true,true,true,true,false,false,true\n" \
|
349
|
+
"#default,t2,,,,,,,,\n" \
|
350
|
+
",result,table,_field,_measurement,_start,_stop,_time,_value,tag\n" \
|
351
|
+
",,0,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:20:00Z,2,test1\n" \
|
352
|
+
",,0,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:21:40Z,2,test1\n" \
|
353
|
+
",,0,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:23:20Z,2,test1\n" \
|
354
|
+
",,0,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:25:00Z,2,test1\n" \
|
355
|
+
",,0,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:26:40Z,2,test1\n" \
|
356
|
+
",,0,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:28:20Z,2,test1\n" \
|
357
|
+
",,0,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:30:00Z,2,test1\n" \
|
358
|
+
",,1,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:20:00Z,2,test2\n" \
|
359
|
+
",,1,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:21:40Z,2,test2\n" \
|
360
|
+
",,1,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:23:20Z,2,test2\n" \
|
361
|
+
",,1,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:25:00Z,2,test2\n" \
|
362
|
+
",,1,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:26:40Z,2,test2\n" \
|
363
|
+
",,1,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:28:20Z,2,test2\n" \
|
364
|
+
',,1,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:30:00Z,2,test2'
|
365
|
+
|
366
|
+
tables = InfluxDB2::FluxCsvParser.new(data).parse.tables
|
367
|
+
|
368
|
+
assert_equal 4, tables.size
|
369
|
+
assert_equal 7, tables[0].records.size
|
370
|
+
assert_equal 7, tables[1].records.size
|
371
|
+
assert_equal 7, tables[2].records.size
|
372
|
+
assert_equal 7, tables[3].records.size
|
373
|
+
end
|
374
|
+
|
375
|
+
def test_table_not_start_at_zero
|
376
|
+
data = "#datatype,string,long,string,string,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,double,string\n" \
|
377
|
+
"#group,false,false,true,true,true,true,false,false,true\n" \
|
378
|
+
"#default,t1,,,,,,,,\n" \
|
379
|
+
",result,table,_field,_measurement,_start,_stop,_time,_value,tag\n" \
|
380
|
+
",,1,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:20:00Z,2,test1\n" \
|
381
|
+
",,1,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:21:40Z,2,test1\n" \
|
382
|
+
",,1,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:23:20Z,2,test1\n" \
|
383
|
+
",,1,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:25:00Z,2,test1\n" \
|
384
|
+
",,1,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:26:40Z,2,test1\n" \
|
385
|
+
",,1,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:28:20Z,2,test1\n" \
|
386
|
+
",,1,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:30:00Z,2,test1\n" \
|
387
|
+
",,2,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:20:00Z,2,test2\n" \
|
388
|
+
",,2,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:21:40Z,2,test2\n" \
|
389
|
+
",,2,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:23:20Z,2,test2\n" \
|
390
|
+
",,2,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:25:00Z,2,test2\n" \
|
391
|
+
",,2,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:26:40Z,2,test2\n" \
|
392
|
+
",,2,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:28:20Z,2,test2\n" \
|
393
|
+
',,2,value,pct,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:30:00Z,2,test2\n'
|
394
|
+
|
395
|
+
tables = InfluxDB2::FluxCsvParser.new(data).parse.tables
|
396
|
+
|
397
|
+
assert_equal 2, tables.size
|
398
|
+
assert_equal 7, tables[0].records.size
|
399
|
+
assert_equal 7, tables[1].records.size
|
400
|
+
end
|
326
401
|
end
|