blob: 2467057d116631df586f58d777b7a91a15c7897f [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package iotdb_go
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// ==================== Aggregation Functions ====================
// TestQuery_AggCount verifies COUNT returns the correct row count.
func TestQuery_AggCount(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
cleanup := setupQueryTestData(t, queryConn, "root.agg_count")
defer cleanup()
row := queryConn.QueryRowContext(context.Background(),
"SELECT COUNT(temp) FROM root.agg_count.d1")
var count int64
err := row.Scan(&count)
require.NoError(t, err)
assert.Equal(t, int64(5), count)
}
// TestQuery_AggSum verifies SUM aggregation.
func TestQuery_AggSum(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
cleanup := setupQueryTestData(t, queryConn, "root.agg_sum")
defer cleanup()
row := queryConn.QueryRowContext(context.Background(),
"SELECT SUM(temp) FROM root.agg_sum.d1")
var sum float64
err := row.Scan(&sum)
require.NoError(t, err)
assert.InDelta(t, 110.0, sum, 0.1)
}
// TestQuery_AggAvg verifies AVG aggregation.
func TestQuery_AggAvg(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
cleanup := setupQueryTestData(t, queryConn, "root.agg_avg")
defer cleanup()
row := queryConn.QueryRowContext(context.Background(),
"SELECT AVG(temp) FROM root.agg_avg.d1")
var avg float64
err := row.Scan(&avg)
require.NoError(t, err)
assert.InDelta(t, 22.0, avg, 0.1)
}
// TestQuery_AggMinMax verifies MIN_VALUE and MAX_VALUE aggregation.
func TestQuery_AggMinMax(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
cleanup := setupQueryTestData(t, queryConn, "root.agg_minmax")
defer cleanup()
row := queryConn.QueryRowContext(context.Background(),
"SELECT MIN_VALUE(temp), MAX_VALUE(temp) FROM root.agg_minmax.d1")
var minTemp, maxTemp float64
err := row.Scan(&minTemp, &maxTemp)
require.NoError(t, err)
assert.InDelta(t, 20.0, minTemp, 0.1)
assert.InDelta(t, 24.0, maxTemp, 0.1)
}
// TestQuery_AggFirstLastValue verifies FIRST_VALUE and LAST_VALUE aggregation.
func TestQuery_AggFirstLastValue(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
cleanup := setupQueryTestData(t, queryConn, "root.agg_firstlast")
defer cleanup()
row := queryConn.QueryRowContext(context.Background(),
"SELECT FIRST_VALUE(temp), LAST_VALUE(temp) FROM root.agg_firstlast.d1")
var first, last float64
err := row.Scan(&first, &last)
require.NoError(t, err)
assert.InDelta(t, 20.0, first, 0.1)
assert.InDelta(t, 24.0, last, 0.1)
}
// TestQuery_AggMinMaxTime verifies MIN_TIME and MAX_TIME return results.
func TestQuery_AggMinMaxTime(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
cleanup := setupQueryTestData(t, queryConn, "root.agg_mintime")
defer cleanup()
rows, err := queryConn.QueryContext(context.Background(),
"SELECT MIN_TIME(temp), MAX_TIME(temp) FROM root.agg_mintime.d1")
require.NoError(t, err)
defer rows.Close()
require.True(t, rows.Next())
require.NoError(t, rows.Err())
}
// TestQuery_MultipleAggregations verifies multiple aggregation functions in one query.
func TestQuery_MultipleAggregations(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
cleanup := setupQueryTestData(t, queryConn, "root.agg_multi")
defer cleanup()
row := queryConn.QueryRowContext(context.Background(),
"SELECT COUNT(temp), SUM(temp), AVG(temp), MIN_VALUE(temp), MAX_VALUE(temp) FROM root.agg_multi.d1")
var count int64
var sum, avg, min, max float64
err := row.Scan(&count, &sum, &avg, &min, &max)
require.NoError(t, err)
assert.Equal(t, int64(5), count)
assert.InDelta(t, 110.0, sum, 0.1)
assert.InDelta(t, 22.0, avg, 0.1)
assert.InDelta(t, 20.0, min, 0.1)
assert.InDelta(t, 24.0, max, 0.1)
}
// ==================== GROUP BY ====================
// TestQuery_GroupByTimeInterval verifies time-interval grouping.
func TestQuery_GroupByTimeInterval(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
cleanup := setupQueryTestData(t, queryConn, "root.group_time")
defer cleanup()
rows, err := queryConn.QueryContext(context.Background(),
"SELECT COUNT(temp), AVG(temp) FROM root.group_time.d1 GROUP BY ([1704067200000, 1704067500000), 2m)")
require.NoError(t, err)
defer rows.Close()
assert.Greater(t, countRows(t, rows), 0)
}
// TestQuery_GroupByWithWhere verifies GROUP BY combined with WHERE.
func TestQuery_GroupByWithWhere(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
cleanup := setupQueryTestData(t, queryConn, "root.group_where")
defer cleanup()
rows, err := queryConn.QueryContext(context.Background(),
"SELECT COUNT(temp) FROM root.group_where.d1 WHERE time < 1704067440000 GROUP BY ([1704067200000, 1704067500000), 2m)")
require.NoError(t, err)
defer rows.Close()
assert.Greater(t, countRows(t, rows), 0)
}
// ==================== ORDER BY ====================
// TestQuery_OrderByTimeDesc verifies descending time ordering.
func TestQuery_OrderByTimeDesc(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
cleanup := setupQueryTestData(t, queryConn, "root.order_time")
defer cleanup()
rows, err := queryConn.QueryContext(context.Background(),
"SELECT temp FROM root.order_time.d1 ORDER BY time DESC")
require.NoError(t, err)
defer rows.Close()
assert.Equal(t, 5, countRows(t, rows))
}
// TestQuery_OrderByTimeAsc verifies ascending time ordering.
func TestQuery_OrderByTimeAsc(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
cleanup := setupQueryTestData(t, queryConn, "root.order_asc")
defer cleanup()
rows, err := queryConn.QueryContext(context.Background(),
"SELECT temp FROM root.order_asc.d1 ORDER BY time ASC")
require.NoError(t, err)
defer rows.Close()
assert.Equal(t, 5, countRows(t, rows))
}
// ==================== LIMIT and OFFSET ====================
// TestQuery_Limit verifies LIMIT restricts row count.
func TestQuery_Limit(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
cleanup := setupQueryTestData(t, queryConn, "root.limit_test")
defer cleanup()
rows, err := queryConn.QueryContext(context.Background(),
"SELECT * FROM root.limit_test.d1 LIMIT 3")
require.NoError(t, err)
defer rows.Close()
assert.Equal(t, 3, countRows(t, rows))
}
// TestQuery_LimitOffset verifies LIMIT with OFFSET skips rows correctly.
func TestQuery_LimitOffset(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
cleanup := setupQueryTestData(t, queryConn, "root.limit_offset")
defer cleanup()
rows, err := queryConn.QueryContext(context.Background(),
"SELECT temp FROM root.limit_offset.d1 ORDER BY time ASC LIMIT 2 OFFSET 2")
require.NoError(t, err)
defer rows.Close()
assert.Equal(t, 2, countRows(t, rows))
}
// ==================== ALIGN BY ====================
// TestQuery_AlignByDevice verifies cross-device alignment.
func TestQuery_AlignByDevice(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
cleanup := setupQueryTestData(t, queryConn, "root.align_device")
defer cleanup()
rows, err := queryConn.QueryContext(context.Background(),
"SELECT temp FROM root.align_device.d1, root.align_device.d2 ALIGN BY DEVICE")
require.NoError(t, err)
defer rows.Close()
assert.GreaterOrEqual(t, countRows(t, rows), 1)
}
// TestQuery_AlignByTime verifies time-based alignment.
func TestQuery_AlignByTime(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
cleanup := setupQueryTestData(t, queryConn, "root.align_time")
defer cleanup()
rows, err := queryConn.QueryContext(context.Background(),
"SELECT * FROM root.align_time.d1 ALIGN BY TIME")
require.NoError(t, err)
defer rows.Close()
assert.Equal(t, 5, countRows(t, rows))
}
// ==================== LAST Query ====================
// TestQuery_LastSingleColumn verifies LAST returns one row per column.
func TestQuery_LastSingleColumn(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
cleanup := setupQueryTestData(t, queryConn, "root.last_single")
defer cleanup()
rows, err := queryConn.QueryContext(context.Background(),
"SELECT LAST temp FROM root.last_single.d1")
require.NoError(t, err)
defer rows.Close()
assert.Equal(t, 1, countRows(t, rows))
}
// TestQuery_LastMultipleColumns verifies LAST for multiple columns.
func TestQuery_LastMultipleColumns(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
cleanup := setupQueryTestData(t, queryConn, "root.last_multi")
defer cleanup()
rows, err := queryConn.QueryContext(context.Background(),
"SELECT LAST temp, hum FROM root.last_multi.d1")
require.NoError(t, err)
defer rows.Close()
assert.Equal(t, 2, countRows(t, rows))
}
// TestQuery_LastAllColumns verifies LAST * returns all columns.
func TestQuery_LastAllColumns(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
cleanup := setupQueryTestData(t, queryConn, "root.last_all")
defer cleanup()
rows, err := queryConn.QueryContext(context.Background(),
"SELECT LAST * FROM root.last_all.d1")
require.NoError(t, err)
defer rows.Close()
assert.GreaterOrEqual(t, countRows(t, rows), 3)
}
// TestQuery_LastWithWhere verifies LAST with time filter.
func TestQuery_LastWithWhere(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
cleanup := setupQueryTestData(t, queryConn, "root.last_where")
defer cleanup()
rows, err := queryConn.QueryContext(context.Background(),
"SELECT LAST temp FROM root.last_where.d1 WHERE time >= 1704067320000")
require.NoError(t, err)
defer rows.Close()
assert.Equal(t, 1, countRows(t, rows))
}
// ==================== Expressions ====================
// TestQuery_ArithmeticExpression verifies arithmetic in SELECT.
func TestQuery_ArithmeticExpression(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
cleanup := setupQueryTestData(t, queryConn, "root.expr_arith")
defer cleanup()
rows, err := queryConn.QueryContext(context.Background(),
"SELECT temp + 10, temp * 2, temp / 2 FROM root.expr_arith.d1")
require.NoError(t, err)
defer rows.Close()
assert.Equal(t, 5, countRows(t, rows))
}
// TestQuery_AggregationExpression verifies arithmetic on aggregation results.
func TestQuery_AggregationExpression(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
cleanup := setupQueryTestData(t, queryConn, "root.expr_agg")
defer cleanup()
row := queryConn.QueryRowContext(context.Background(),
"SELECT AVG(temp) + 1, SUM(temp) * 2 FROM root.expr_agg.d1")
var avgPlus, sumTimes float64
err := row.Scan(&avgPlus, &sumTimes)
require.NoError(t, err)
assert.InDelta(t, 23.0, avgPlus, 0.1)
assert.InDelta(t, 220.0, sumTimes, 0.1)
}
// ==================== Metadata ====================
// TestQuery_ShowDatabases verifies SHOW DATABASES returns results.
func TestQuery_ShowDatabases(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
rows, err := queryConn.QueryContext(context.Background(), "SHOW DATABASES")
require.NoError(t, err)
defer rows.Close()
assert.GreaterOrEqual(t, countRows(t, rows), 1)
}
// TestQuery_ShowTimeseries verifies SHOW TIMESERIES returns correct count.
func TestQuery_ShowTimeseries(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
cleanup := setupQueryTestData(t, queryConn, "root.show_ts")
defer cleanup()
rows, err := queryConn.QueryContext(context.Background(),
"SHOW TIMESERIES root.show_ts.**")
require.NoError(t, err)
defer rows.Close()
assert.Equal(t, 4, countRows(t, rows))
}
// TestQuery_ColumnsMetadata verifies column names are retrievable from result set.
func TestQuery_ColumnsMetadata(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
cleanup := setupQueryTestData(t, queryConn, "root.col_meta")
defer cleanup()
rows, err := queryConn.QueryContext(context.Background(),
"SELECT * FROM root.col_meta.d1")
require.NoError(t, err)
defer rows.Close()
cols, err := rows.Columns()
require.NoError(t, err)
assert.GreaterOrEqual(t, len(cols), 3)
}