gotidb/pkg/engine/memory/memory_test.go

246 lines
6.1 KiB
Go

package memory
import (
"context"
"testing"
"time"
"git.pyer.club/kingecg/gotidb/pkg/engine"
)
func TestMemoryEngine(t *testing.T) {
// 创建引擎配置
config := engine.NewEngineConfig()
// 创建内存引擎
eng, err := NewMemoryEngine(config)
if err != nil {
t.Fatalf("Failed to create memory engine: %v", err)
}
// 打开引擎
if err := eng.Open(); err != nil {
t.Fatalf("Failed to open engine: %v", err)
}
defer eng.Close()
// 测试写入单个数据点
t.Run("WritePoint", func(t *testing.T) {
point := engine.DataPoint{
DeviceID: "device001",
MetricCode: "temperature",
Labels: map[string]string{
"location": "room1",
},
Value: 25.5,
Timestamp: time.Now().UnixNano(),
}
if err := eng.WritePoint(context.Background(), point); err != nil {
t.Fatalf("Failed to write point: %v", err)
}
// 刷新缓冲区确保数据写入
if err := eng.Flush(); err != nil {
t.Fatalf("Failed to flush: %v", err)
}
// 查询最新数据
query := engine.NewQueryBuilder().
ForMetric("temperature").
WithTag("location", engine.OpEqual, "room1").
Build()
query.Type = engine.QueryTypeLatest
result, err := eng.Query(context.Background(), query)
if err != nil {
t.Fatalf("Failed to query latest data: %v", err)
}
tsResult, ok := result.(*engine.TimeSeriesResult)
if !ok {
t.Fatalf("Expected TimeSeriesResult, got %T", result)
}
if len(tsResult.Points) != 1 {
t.Fatalf("Expected 1 point, got %d", len(tsResult.Points))
}
if tsResult.Points[0].Value != 25.5 {
t.Errorf("Expected value 25.5, got %.2f", tsResult.Points[0].Value)
}
})
// 测试批量写入
t.Run("WriteBatch", func(t *testing.T) {
now := time.Now()
var points []engine.DataPoint
for i := 0; i < 10; i++ {
points = append(points, engine.DataPoint{
DeviceID: "device002",
MetricCode: "cpu",
Labels: map[string]string{
"host": "server1",
},
Value: float64(i * 10),
Timestamp: now.Add(time.Duration(i) * time.Second).UnixNano(),
})
}
if err := eng.WriteBatch(context.Background(), points); err != nil {
t.Fatalf("Failed to write batch: %v", err)
}
// 查询原始数据
query := engine.NewQueryBuilder().
ForMetric("cpu").
WithTimeRange(now.Add(-1*time.Hour).UnixNano(), now.Add(1*time.Hour).UnixNano()).
WithTag("host", engine.OpEqual, "server1").
Build()
result, err := eng.Query(context.Background(), query)
if err != nil {
t.Fatalf("Failed to query raw data: %v", err)
}
tsResult, ok := result.(*engine.TimeSeriesResult)
if !ok {
t.Fatalf("Expected TimeSeriesResult, got %T", result)
}
if len(tsResult.Points) != 10 {
t.Fatalf("Expected 10 points, got %d", len(tsResult.Points))
}
})
// 测试聚合查询
t.Run("AggregateQuery", func(t *testing.T) {
now := time.Now()
var points []engine.DataPoint
for i := 0; i < 10; i++ {
points = append(points, engine.DataPoint{
DeviceID: "device003",
MetricCode: "memory",
Labels: map[string]string{
"host": "server2",
},
Value: float64(i * 10),
Timestamp: now.Add(time.Duration(i) * time.Second).UnixNano(),
})
}
if err := eng.WriteBatch(context.Background(), points); err != nil {
t.Fatalf("Failed to write batch: %v", err)
}
// 查询聚合数据
query := engine.NewQueryBuilder().
ForMetric("memory").
WithTimeRange(now.Add(-1*time.Hour).UnixNano(), now.Add(1*time.Hour).UnixNano()).
WithTag("host", engine.OpEqual, "server2").
WithAggregation(engine.AggAvg, 1*time.Minute).
Build()
result, err := eng.Query(context.Background(), query)
if err != nil {
t.Fatalf("Failed to query aggregate data: %v", err)
}
aggResult, ok := result.(*engine.AggregateResult)
if !ok {
t.Fatalf("Expected AggregateResult, got %T", result)
}
if len(aggResult.Groups) == 0 {
t.Fatalf("Expected at least one aggregate group")
}
})
// 测试引擎统计信息
t.Run("EngineStats", func(t *testing.T) {
stats := eng.Stats()
if stats.PointsCount == 0 {
t.Errorf("Expected non-zero points count")
}
})
// 测试引擎能力
t.Run("EngineCapabilities", func(t *testing.T) {
caps := eng.Capabilities()
if !caps.SupportsCompression {
t.Errorf("Expected compression support")
}
if caps.SupportsPersistence {
t.Errorf("Memory engine should not support persistence")
}
})
}
func TestCircularBuffer(t *testing.T) {
// 创建引擎配置
config := engine.NewEngineConfig()
memConfig := config.MemoryConfig()
memConfig.MaxPointsPerSeries = 5 // 设置为较小的值以便测试
// 创建内存引擎
eng, err := NewMemoryEngine(config)
if err != nil {
t.Fatalf("Failed to create memory engine: %v", err)
}
// 打开引擎
if err := eng.Open(); err != nil {
t.Fatalf("Failed to open engine: %v", err)
}
defer eng.Close()
// 写入超过缓冲区容量的数据点
now := time.Now()
var points []engine.DataPoint
for i := 0; i < 10; i++ {
points = append(points, engine.DataPoint{
DeviceID: "device004",
MetricCode: "disk",
Labels: map[string]string{
"path": "/data",
},
Value: float64(i),
Timestamp: now.Add(time.Duration(i) * time.Second).UnixNano(),
})
}
if err := eng.WriteBatch(context.Background(), points); err != nil {
t.Fatalf("Failed to write batch: %v", err)
}
// 查询原始数据
query := engine.NewQueryBuilder().
ForMetric("disk").
WithTimeRange(now.Add(-1*time.Hour).UnixNano(), now.Add(1*time.Hour).UnixNano()).
WithTag("path", engine.OpEqual, "/data").
Build()
result, err := eng.Query(context.Background(), query)
if err != nil {
t.Fatalf("Failed to query raw data: %v", err)
}
tsResult, ok := result.(*engine.TimeSeriesResult)
if !ok {
t.Fatalf("Expected TimeSeriesResult, got %T", result)
}
// 应该只返回最近的5个点
if len(tsResult.Points) != 5 {
t.Fatalf("Expected 5 points (MaxPointsPerSeries), got %d", len(tsResult.Points))
}
// 检查返回的是最新的5个点
for i, point := range tsResult.Points {
expectedValue := float64(i + 5) // 5-9
if point.Value != expectedValue {
t.Errorf("Expected point value %.1f, got %.1f", expectedValue, point.Value)
}
}
}