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) } } }