Skip to main content
Glama
FreePeak

Multi Database MCP Server

hypertable_test.go13.5 kB
package timescale import ( "context" "errors" "testing" ) func TestCreateHypertable(t *testing.T) { mockDB := NewMockDB() tsdb := &DB{ Database: mockDB, isTimescaleDB: true, } ctx := context.Background() // Test basic hypertable creation config := HypertableConfig{ TableName: "test_table", TimeColumn: "time", ChunkTimeInterval: "1 day", CreateIfNotExists: true, } err := tsdb.CreateHypertable(ctx, config) if err != nil { t.Fatalf("Failed to create hypertable: %v", err) } // Check that the correct query was executed query, _ := mockDB.GetLastQuery() AssertQueryContains(t, query, "create_hypertable") AssertQueryContains(t, query, "test_table") AssertQueryContains(t, query, "time") AssertQueryContains(t, query, "chunk_time_interval") AssertQueryContains(t, query, "1 day") // Test with partitioning config = HypertableConfig{ TableName: "test_table", TimeColumn: "time", ChunkTimeInterval: "1 day", PartitioningColumn: "device_id", SpacePartitions: 4, } err = tsdb.CreateHypertable(ctx, config) if err != nil { t.Fatalf("Failed to create hypertable with partitioning: %v", err) } // Check that the correct query was executed query, _ = mockDB.GetLastQuery() AssertQueryContains(t, query, "create_hypertable") AssertQueryContains(t, query, "partition_column") AssertQueryContains(t, query, "device_id") AssertQueryContains(t, query, "number_partitions") // Test with if_not_exists and migrate_data config = HypertableConfig{ TableName: "test_table", TimeColumn: "time", IfNotExists: true, MigrateData: true, } err = tsdb.CreateHypertable(ctx, config) if err != nil { t.Fatalf("Failed to create hypertable with extra options: %v", err) } // Check that the correct query was executed query, _ = mockDB.GetLastQuery() AssertQueryContains(t, query, "if_not_exists => TRUE") AssertQueryContains(t, query, "migrate_data => TRUE") // Test when TimescaleDB is not available tsdb.isTimescaleDB = false err = tsdb.CreateHypertable(ctx, config) if err == nil { t.Error("Expected error when TimescaleDB is not available, got nil") } // Test execution error tsdb.isTimescaleDB = true mockDB.RegisterQueryResult("SELECT create_hypertable(", nil, errors.New("mocked error")) err = tsdb.CreateHypertable(ctx, config) if err == nil { t.Error("Expected query error, got nil") } } func TestAddDimension(t *testing.T) { mockDB := NewMockDB() tsdb := &DB{ Database: mockDB, isTimescaleDB: true, } ctx := context.Background() // Test adding a dimension err := tsdb.AddDimension(ctx, "test_table", "device_id", 4) if err != nil { t.Fatalf("Failed to add dimension: %v", err) } // Check that the correct query was executed query, _ := mockDB.GetLastQuery() AssertQueryContains(t, query, "add_dimension") AssertQueryContains(t, query, "test_table") AssertQueryContains(t, query, "device_id") AssertQueryContains(t, query, "number_partitions => 4") // Test when TimescaleDB is not available tsdb.isTimescaleDB = false err = tsdb.AddDimension(ctx, "test_table", "device_id", 4) if err == nil { t.Error("Expected error when TimescaleDB is not available, got nil") } // Test execution error tsdb.isTimescaleDB = true mockDB.RegisterQueryResult("SELECT add_dimension(", nil, errors.New("mocked error")) err = tsdb.AddDimension(ctx, "test_table", "device_id", 4) if err == nil { t.Error("Expected query error, got nil") } } func TestListHypertables(t *testing.T) { mockDB := NewMockDB() tsdb := &DB{ Database: mockDB, isTimescaleDB: true, } ctx := context.Background() // Prepare mock data mockResult := []map[string]interface{}{ { "table_name": "test_table", "schema_name": "public", "time_column": "time", "num_dimensions": 2, "space_column": "device_id", }, { "table_name": "test_table2", "schema_name": "public", "time_column": "timestamp", "num_dimensions": 1, "space_column": nil, }, } // Register different result patterns for different queries mockDB.RegisterQueryResult("FROM _timescaledb_catalog.hypertable h", mockResult, nil) mockDB.RegisterQueryResult("FROM timescaledb_information.compression_settings", []map[string]interface{}{ {"is_compressed": true}, }, nil) mockDB.RegisterQueryResult("FROM timescaledb_information.jobs", []map[string]interface{}{ {"has_retention": true}, }, nil) // Test listing hypertables hypertables, err := tsdb.ListHypertables(ctx) if err != nil { t.Fatalf("Failed to list hypertables: %v", err) } // Check the results if len(hypertables) != 2 { t.Errorf("Expected 2 hypertables, got %d", len(hypertables)) } if hypertables[0].TableName != "test_table" { t.Errorf("Expected TableName to be 'test_table', got '%s'", hypertables[0].TableName) } if hypertables[0].TimeColumn != "time" { t.Errorf("Expected TimeColumn to be 'time', got '%s'", hypertables[0].TimeColumn) } if hypertables[0].SpaceColumn != "device_id" { t.Errorf("Expected SpaceColumn to be 'device_id', got '%s'", hypertables[0].SpaceColumn) } if hypertables[0].NumDimensions != 2 { t.Errorf("Expected NumDimensions to be 2, got %d", hypertables[0].NumDimensions) } if !hypertables[0].CompressionEnabled { t.Error("Expected CompressionEnabled to be true, got false") } if !hypertables[0].RetentionEnabled { t.Error("Expected RetentionEnabled to be true, got false") } // Test when TimescaleDB is not available tsdb.isTimescaleDB = false _, err = tsdb.ListHypertables(ctx) if err == nil { t.Error("Expected error when TimescaleDB is not available, got nil") } // Test execution error tsdb.isTimescaleDB = true mockDB.RegisterQueryResult("FROM _timescaledb_catalog.hypertable h", nil, errors.New("mocked error")) _, err = tsdb.ListHypertables(ctx) if err == nil { t.Error("Expected query error, got nil") } } func TestGetHypertable(t *testing.T) { mockDB := NewMockDB() tsdb := &DB{ Database: mockDB, isTimescaleDB: true, } ctx := context.Background() // Prepare mock data - Set up the correct result by using RegisterQueryResult mockResult := []map[string]interface{}{ { "table_name": "test_table", "schema_name": "public", "time_column": "time", "num_dimensions": int64(2), "space_column": "device_id", }, } // Register the query result pattern for the main query mockDB.RegisterQueryResult("WHERE h.table_name = 'test_table'", mockResult, nil) // Register results for the compression check mockDB.RegisterQueryResult("FROM timescaledb_information.compression_settings", []map[string]interface{}{ {"is_compressed": true}, }, nil) // Register results for the retention policy check mockDB.RegisterQueryResult("FROM timescaledb_information.jobs", []map[string]interface{}{ {"has_retention": true}, }, nil) // Test getting a hypertable hypertable, err := tsdb.GetHypertable(ctx, "test_table") if err != nil { t.Fatalf("Failed to get hypertable: %v", err) } // Check the results if hypertable.TableName != "test_table" { t.Errorf("Expected TableName to be 'test_table', got '%s'", hypertable.TableName) } if hypertable.TimeColumn != "time" { t.Errorf("Expected TimeColumn to be 'time', got '%s'", hypertable.TimeColumn) } if hypertable.SpaceColumn != "device_id" { t.Errorf("Expected SpaceColumn to be 'device_id', got '%s'", hypertable.SpaceColumn) } if hypertable.NumDimensions != 2 { t.Errorf("Expected NumDimensions to be 2, got %d", hypertable.NumDimensions) } if !hypertable.CompressionEnabled { t.Error("Expected CompressionEnabled to be true, got false") } if !hypertable.RetentionEnabled { t.Error("Expected RetentionEnabled to be true, got false") } // Test when TimescaleDB is not available tsdb.isTimescaleDB = false _, err = tsdb.GetHypertable(ctx, "test_table") if err == nil { t.Error("Expected error when TimescaleDB is not available, got nil") } // Test execution error tsdb.isTimescaleDB = true mockDB.RegisterQueryResult("WHERE h.table_name = 'test_table'", nil, errors.New("mocked error")) _, err = tsdb.GetHypertable(ctx, "test_table") if err == nil { t.Error("Expected query error, got nil") } // Test table not found - Create a new mock to avoid interference newMockDB := NewMockDB() newMockDB.SetTimescaleAvailable(true) tsdb.Database = newMockDB // Register an empty result for the "not_found" table newMockDB.RegisterQueryResult("WHERE h.table_name = 'not_found'", []map[string]interface{}{}, nil) _, err = tsdb.GetHypertable(ctx, "not_found") if err == nil { t.Error("Expected error for non-existent table, got nil") } } func TestDropHypertable(t *testing.T) { mockDB := NewMockDB() tsdb := &DB{ Database: mockDB, isTimescaleDB: true, } ctx := context.Background() // Test dropping a hypertable err := tsdb.DropHypertable(ctx, "test_table", false) if err != nil { t.Fatalf("Failed to drop hypertable: %v", err) } // Check that the correct query was executed query, _ := mockDB.GetLastQuery() AssertQueryContains(t, query, "DROP TABLE test_table") // Test dropping with CASCADE err = tsdb.DropHypertable(ctx, "test_table", true) if err != nil { t.Fatalf("Failed to drop hypertable with CASCADE: %v", err) } // Check that the correct query was executed query, _ = mockDB.GetLastQuery() AssertQueryContains(t, query, "DROP TABLE test_table CASCADE") // Test when TimescaleDB is not available tsdb.isTimescaleDB = false err = tsdb.DropHypertable(ctx, "test_table", false) if err == nil { t.Error("Expected error when TimescaleDB is not available, got nil") } // Test execution error tsdb.isTimescaleDB = true mockDB.RegisterQueryResult("DROP TABLE", nil, errors.New("mocked error")) err = tsdb.DropHypertable(ctx, "test_table", false) if err == nil { t.Error("Expected query error, got nil") } } func TestCheckIfHypertable(t *testing.T) { mockDB := NewMockDB() tsdb := &DB{ Database: mockDB, isTimescaleDB: true, } ctx := context.Background() // Prepare mock data mockResultTrue := []map[string]interface{}{ {"is_hypertable": true}, } mockResultFalse := []map[string]interface{}{ {"is_hypertable": false}, } // Test table is a hypertable mockDB.RegisterQueryResult("WHERE table_name = 'test_table'", mockResultTrue, nil) isHypertable, err := tsdb.CheckIfHypertable(ctx, "test_table") if err != nil { t.Fatalf("Failed to check if hypertable: %v", err) } if !isHypertable { t.Error("Expected table to be a hypertable, got false") } // Test table is not a hypertable mockDB.RegisterQueryResult("WHERE table_name = 'regular_table'", mockResultFalse, nil) isHypertable, err = tsdb.CheckIfHypertable(ctx, "regular_table") if err != nil { t.Fatalf("Failed to check if hypertable: %v", err) } if isHypertable { t.Error("Expected table not to be a hypertable, got true") } // Test when TimescaleDB is not available tsdb.isTimescaleDB = false _, err = tsdb.CheckIfHypertable(ctx, "test_table") if err == nil { t.Error("Expected error when TimescaleDB is not available, got nil") } // Test execution error tsdb.isTimescaleDB = true mockDB.RegisterQueryResult("WHERE table_name = 'error_table'", nil, errors.New("mocked error")) _, err = tsdb.CheckIfHypertable(ctx, "error_table") if err == nil { t.Error("Expected query error, got nil") } // Test unexpected result structure mockDB.RegisterQueryResult("WHERE table_name = 'bad_structure'", []map[string]interface{}{}, nil) _, err = tsdb.CheckIfHypertable(ctx, "bad_structure") if err == nil { t.Error("Expected error for bad result structure, got nil") } } func TestRecentChunks(t *testing.T) { mockDB := NewMockDB() tsdb := &DB{ Database: mockDB, isTimescaleDB: true, } ctx := context.Background() // Prepare mock data mockResult := []map[string]interface{}{ { "chunk_name": "_hyper_1_1_chunk", "range_start": "2023-01-01 00:00:00", "range_end": "2023-01-02 00:00:00", "is_compressed": false, }, { "chunk_name": "_hyper_1_2_chunk", "range_start": "2023-01-02 00:00:00", "range_end": "2023-01-03 00:00:00", "is_compressed": true, }, } // Register mock result mockDB.RegisterQueryResult("FROM timescaledb_information.chunks", mockResult, nil) // Test getting recent chunks _, err := tsdb.RecentChunks(ctx, "test_table", 2) if err != nil { t.Fatalf("Failed to get recent chunks: %v", err) } // Check that a query with the right table name and limit was executed query, _ := mockDB.GetLastQuery() AssertQueryContains(t, query, "hypertable_name = 'test_table'") AssertQueryContains(t, query, "LIMIT 2") // Test with default limit _, err = tsdb.RecentChunks(ctx, "test_table", 0) if err != nil { t.Fatalf("Failed to get recent chunks with default limit: %v", err) } query, _ = mockDB.GetLastQuery() AssertQueryContains(t, query, "LIMIT 10") // Test when TimescaleDB is not available tsdb.isTimescaleDB = false _, err = tsdb.RecentChunks(ctx, "test_table", 2) if err == nil { t.Error("Expected error when TimescaleDB is not available, got nil") } // Test execution error tsdb.isTimescaleDB = true mockDB.RegisterQueryResult("FROM timescaledb_information.chunks", nil, errors.New("mocked error")) _, err = tsdb.RecentChunks(ctx, "test_table", 2) if err == nil { t.Error("Expected query error, got nil") } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/FreePeak/db-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server