blob: 46232990bf420c600c20a027b035fb81af2b9548 [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"
"database/sql"
"database/sql/driver"
"errors"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var stdConn *sql.DB
func init() {
var err error
stdConn, err = sql.Open("iotdb", defaultAddress)
if err != nil {
panic(err)
}
}
// ==================== INSERT Operations ====================
// TestStd_BasicInsert verifies a single-row INSERT with mixed types.
func TestStd_BasicInsert(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
sg := "root.std_test"
_, err := stdConn.ExecContext(context.Background(), "CREATE DATABASE "+sg)
require.NoError(t, err)
defer func() { _, _ = stdConn.ExecContext(context.Background(), "DELETE DATABASE "+sg) }()
_, err = stdConn.ExecContext(context.Background(),
"CREATE TIMESERIES "+sg+".d1.status WITH DATATYPE=BOOLEAN, ENCODING=PLAIN")
require.NoError(t, err)
_, err = stdConn.ExecContext(context.Background(),
"CREATE TIMESERIES "+sg+".d1.temp WITH DATATYPE=FLOAT, ENCODING=PLAIN")
require.NoError(t, err)
_, err = stdConn.ExecContext(context.Background(),
"INSERT INTO "+sg+".d1(timestamp, status, temp) VALUES (?, ?, ?)",
1, true, 25.5)
require.NoError(t, err)
// Verify inserted data can be read back
rows, err := stdConn.QueryContext(context.Background(), "SELECT status, temp FROM "+sg+".d1")
require.NoError(t, err)
defer rows.Close()
require.True(t, rows.Next())
var ts int64
var status bool
var temp float64
err = rows.Scan(&ts, &status, &temp)
require.NoError(t, err)
assert.True(t, status)
assert.InDelta(t, 25.5, temp, 0.1)
require.NoError(t, rows.Err())
}
// TestStd_MultiValueInsert verifies inserting multiple rows in a single statement.
func TestStd_MultiValueInsert(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
sg := "root.std_multi"
_, err := stdConn.ExecContext(context.Background(), "CREATE DATABASE "+sg)
require.NoError(t, err)
defer func() { _, _ = stdConn.ExecContext(context.Background(), "DELETE DATABASE "+sg) }()
_, err = stdConn.ExecContext(context.Background(),
"CREATE TIMESERIES "+sg+".d1.status WITH DATATYPE=BOOLEAN, ENCODING=PLAIN")
require.NoError(t, err)
_, err = stdConn.ExecContext(context.Background(),
"CREATE TIMESERIES "+sg+".d1.temp WITH DATATYPE=FLOAT, ENCODING=PLAIN")
require.NoError(t, err)
_, err = stdConn.ExecContext(context.Background(),
"INSERT INTO "+sg+".d1(timestamp, status, temp) VALUES (?, ?, ?), (?, ?, ?)",
1, true, 25.0,
2, false, 26.0)
require.NoError(t, err)
// Verify both rows exist
rows, err := stdConn.QueryContext(context.Background(), "SELECT temp FROM "+sg+".d1 ORDER BY time ASC")
require.NoError(t, err)
defer rows.Close()
var count int
for rows.Next() {
count++
}
assert.Equal(t, 2, count)
require.NoError(t, rows.Err())
}
// TestStd_InsertTypes verifies INSERT with INT64 and FLOAT types.
func TestStd_InsertTypes(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
sg := "root.std_types"
_, err := stdConn.ExecContext(context.Background(), "CREATE DATABASE "+sg)
require.NoError(t, err)
defer func() { _, _ = stdConn.ExecContext(context.Background(), "DELETE DATABASE "+sg) }()
_, err = stdConn.ExecContext(context.Background(),
"CREATE TIMESERIES "+sg+".d1.int_val WITH DATATYPE=INT64, ENCODING=PLAIN")
require.NoError(t, err)
_, err = stdConn.ExecContext(context.Background(),
"CREATE TIMESERIES "+sg+".d1.float_val WITH DATATYPE=FLOAT, ENCODING=PLAIN")
require.NoError(t, err)
_, err = stdConn.ExecContext(context.Background(),
"INSERT INTO "+sg+".d1(timestamp, int_val, float_val) VALUES (?, ?, ?)",
1, 1718193600000, 99.9)
require.NoError(t, err)
// Verify values
row := stdConn.QueryRowContext(context.Background(),
"SELECT int_val, float_val FROM "+sg+".d1")
var ts int64
var intVal int64
var floatVal float64
err = row.Scan(&ts, &intVal, &floatVal)
require.NoError(t, err)
assert.Equal(t, int64(1718193600000), intVal)
assert.InDelta(t, 99.9, floatVal, 0.1)
}
// ==================== Basic Query ====================
// TestStd_QueryBasic verifies a round-trip INSERT then SELECT.
func TestStd_QueryBasic(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
sg := "root.std_query"
_, err := stdConn.ExecContext(context.Background(), "CREATE DATABASE "+sg)
require.NoError(t, err)
defer func() { _, _ = stdConn.ExecContext(context.Background(), "DELETE DATABASE "+sg) }()
_, err = stdConn.ExecContext(context.Background(),
"CREATE TIMESERIES "+sg+".d1.temp WITH DATATYPE=FLOAT, ENCODING=PLAIN")
require.NoError(t, err)
_, err = stdConn.ExecContext(context.Background(),
"INSERT INTO "+sg+".d1(timestamp, temp) VALUES (?, ?)",
1704067200000, 25.5)
require.NoError(t, err)
rows, err := stdConn.QueryContext(context.Background(), "SELECT temp FROM "+sg+".d1")
require.NoError(t, err)
defer rows.Close()
require.True(t, rows.Next())
var ts int64
var temp float64
err = rows.Scan(&ts, &temp)
require.NoError(t, err)
assert.InDelta(t, 25.5, temp, 0.1)
require.NoError(t, rows.Err())
}
// ==================== Struct Scanning ====================
// TestStd_ScanStruct verifies scanning multiple columns into struct fields.
func TestStd_ScanStruct(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
sg := "root.std_scan"
_, err := stdConn.ExecContext(context.Background(), "CREATE DATABASE "+sg)
require.NoError(t, err)
defer func() { _, _ = stdConn.ExecContext(context.Background(), "DELETE DATABASE "+sg) }()
_, err = stdConn.ExecContext(context.Background(),
"CREATE TIMESERIES "+sg+".d1.temp WITH DATATYPE=FLOAT, ENCODING=PLAIN")
require.NoError(t, err)
_, err = stdConn.ExecContext(context.Background(),
"CREATE TIMESERIES "+sg+".d1.hum WITH DATATYPE=DOUBLE, ENCODING=PLAIN")
require.NoError(t, err)
_, err = stdConn.ExecContext(context.Background(),
"INSERT INTO "+sg+".d1(timestamp, temp, hum) VALUES (?, ?, ?)",
1704067200000, 25.5, 60.5)
require.NoError(t, err)
rows, err := stdConn.QueryContext(context.Background(), "SELECT temp, hum FROM "+sg+".d1")
require.NoError(t, err)
defer rows.Close()
require.True(t, rows.Next())
type Reading struct {
Time int64
Temp float64
Hum float64
}
var r Reading
err = rows.Scan(&r.Time, &r.Temp, &r.Hum)
require.NoError(t, err)
assert.InDelta(t, 25.5, r.Temp, 0.1)
assert.InDelta(t, 60.5, r.Hum, 0.1)
require.NoError(t, rows.Err())
}
// ==================== Metadata Queries ====================
// TestStd_ShowDatabases verifies SHOW DATABASES returns at least one result.
func TestStd_ShowDatabases(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}
rows, err := stdConn.QueryContext(context.Background(), "SHOW DATABASES")
require.NoError(t, err)
defer rows.Close()
var count int
for rows.Next() {
count++
}
assert.GreaterOrEqual(t, count, 1)
require.NoError(t, rows.Err())
}
// ==================== Transactions ====================
// TestStd_BeginUnsupported verifies that Begin reports transactions as
// unsupported rather than returning a fake no-op transaction.
func TestStd_BeginUnsupported(t *testing.T) {
tx, err := (&stdDriver{}).Begin()
assert.Nil(t, tx)
assert.ErrorIs(t, err, ErrTransactionsUnsupported)
}
// TestStd_BeginTxUnsupported verifies the same for the context-aware BeginTx.
func TestStd_BeginTxUnsupported(t *testing.T) {
tx, err := (&stdDriver{}).BeginTx(context.Background(), driver.TxOptions{})
assert.Nil(t, tx)
assert.ErrorIs(t, err, ErrTransactionsUnsupported)
}
// TestStd_DBBeginUnsupported verifies the error surfaces through database/sql.
func TestStd_DBBeginUnsupported(t *testing.T) {
_, err := stdConn.Begin()
assert.True(t, errors.Is(err, ErrTransactionsUnsupported))
}