mirror of
https://github.com/DeBrosOfficial/network.git
synced 2025-12-13 00:58:50 +00:00
330 lines
9.4 KiB
Go
330 lines
9.4 KiB
Go
package e2e
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/DeBrosOfficial/network/pkg/client"
|
|
"github.com/DeBrosOfficial/network/pkg/config"
|
|
"github.com/DeBrosOfficial/network/pkg/node"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// TestHibernationCycle tests that databases hibernate after idle timeout
|
|
func TestHibernationCycle(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("Skipping e2e test in short mode")
|
|
}
|
|
|
|
// Setup test environment
|
|
testDir := filepath.Join(os.TempDir(), fmt.Sprintf("debros_test_hibernate_%d", time.Now().Unix()))
|
|
defer os.RemoveAll(testDir)
|
|
|
|
logger, _ := zap.NewDevelopment()
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
|
defer cancel()
|
|
|
|
// Start 3 nodes with short hibernation timeout
|
|
nodes := make([]*node.Node, 3)
|
|
for i := 0; i < 3; i++ {
|
|
cfg := config.DefaultConfig()
|
|
cfg.Node.DataDir = filepath.Join(testDir, fmt.Sprintf("node%d", i+1))
|
|
cfg.P2P.ListenAddresses = []string{fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", 14001+i)}
|
|
cfg.Database.ReplicationFactor = 3
|
|
cfg.Database.MaxDatabases = 10
|
|
cfg.Database.HibernationTimeout = 10 * time.Second // Short timeout for testing
|
|
cfg.Database.PortRangeHTTPStart = 15001 + (i * 100)
|
|
cfg.Database.PortRangeHTTPEnd = 15010 + (i * 100)
|
|
cfg.Database.PortRangeRaftStart = 17001 + (i * 100)
|
|
cfg.Database.PortRangeRaftEnd = 17010 + (i * 100)
|
|
|
|
if i > 0 {
|
|
bootstrapAddr := nodes[0].Host().Addrs()[0].String() + "/p2p/" + nodes[0].Host().ID().String()
|
|
cfg.P2P.BootstrapPeers = []string{bootstrapAddr}
|
|
}
|
|
|
|
n, err := node.NewNode(cfg, logger)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create node %d: %v", i+1, err)
|
|
}
|
|
|
|
if err := n.Start(ctx); err != nil {
|
|
t.Fatalf("Failed to start node %d: %v", i+1, err)
|
|
}
|
|
defer n.Stop()
|
|
|
|
nodes[i] = n
|
|
}
|
|
|
|
time.Sleep(5 * time.Second)
|
|
|
|
// Create client
|
|
bootstrapAddr := nodes[0].Host().Addrs()[0].String() + "/p2p/" + nodes[0].Host().ID().String()
|
|
cli, err := client.NewClient(ctx, client.ClientConfig{
|
|
AppName: "testapp",
|
|
BootstrapPeers: []string{bootstrapAddr},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Failed to create client: %v", err)
|
|
}
|
|
defer cli.Close()
|
|
|
|
// Create database and write data
|
|
db := cli.Database("testdb")
|
|
|
|
_, err = db.WriteOne("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)")
|
|
if err != nil {
|
|
t.Fatalf("Failed to create table: %v", err)
|
|
}
|
|
|
|
_, err = db.WriteOne("INSERT INTO users (name) VALUES ('Alice')")
|
|
if err != nil {
|
|
t.Fatalf("Failed to insert data: %v", err)
|
|
}
|
|
|
|
t.Log("Data written, waiting for hibernation...")
|
|
|
|
// Wait for hibernation (timeout + grace period)
|
|
time.Sleep(20 * time.Second)
|
|
|
|
t.Log("Hibernation period elapsed, database should be hibernating")
|
|
|
|
// Note: In a real test, we would check the metadata store to verify hibernation status
|
|
// For now, we just verify the data directory still exists
|
|
for i := 0; i < 3; i++ {
|
|
dbDir := filepath.Join(testDir, fmt.Sprintf("node%d/testapp_testdb", i+1))
|
|
if _, err := os.Stat(dbDir); os.IsNotExist(err) {
|
|
t.Errorf("Expected database directory to exist on node %d after hibernation", i+1)
|
|
}
|
|
}
|
|
|
|
t.Log("Hibernation cycle test passed")
|
|
}
|
|
|
|
// TestWakeUpCycle tests that hibernated databases wake up on access
|
|
func TestWakeUpCycle(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("Skipping e2e test in short mode")
|
|
}
|
|
|
|
// Setup test environment
|
|
testDir := filepath.Join(os.TempDir(), fmt.Sprintf("debros_test_wakeup_%d", time.Now().Unix()))
|
|
defer os.RemoveAll(testDir)
|
|
|
|
logger, _ := zap.NewDevelopment()
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
|
defer cancel()
|
|
|
|
// Start 3 nodes with short hibernation timeout
|
|
nodes := make([]*node.Node, 3)
|
|
for i := 0; i < 3; i++ {
|
|
cfg := config.DefaultConfig()
|
|
cfg.Node.DataDir = filepath.Join(testDir, fmt.Sprintf("node%d", i+1))
|
|
cfg.P2P.ListenAddresses = []string{fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", 14001+i)}
|
|
cfg.Database.ReplicationFactor = 3
|
|
cfg.Database.MaxDatabases = 10
|
|
cfg.Database.HibernationTimeout = 10 * time.Second
|
|
cfg.Database.PortRangeHTTPStart = 15001 + (i * 100)
|
|
cfg.Database.PortRangeHTTPEnd = 15010 + (i * 100)
|
|
cfg.Database.PortRangeRaftStart = 17001 + (i * 100)
|
|
cfg.Database.PortRangeRaftEnd = 17010 + (i * 100)
|
|
|
|
if i > 0 {
|
|
bootstrapAddr := nodes[0].Host().Addrs()[0].String() + "/p2p/" + nodes[0].Host().ID().String()
|
|
cfg.P2P.BootstrapPeers = []string{bootstrapAddr}
|
|
}
|
|
|
|
n, err := node.NewNode(cfg, logger)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create node %d: %v", i+1, err)
|
|
}
|
|
|
|
if err := n.Start(ctx); err != nil {
|
|
t.Fatalf("Failed to start node %d: %v", i+1, err)
|
|
}
|
|
defer n.Stop()
|
|
|
|
nodes[i] = n
|
|
}
|
|
|
|
time.Sleep(5 * time.Second)
|
|
|
|
// Create client
|
|
bootstrapAddr := nodes[0].Host().Addrs()[0].String() + "/p2p/" + nodes[0].Host().ID().String()
|
|
cli, err := client.NewClient(ctx, client.ClientConfig{
|
|
AppName: "testapp",
|
|
BootstrapPeers: []string{bootstrapAddr},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Failed to create client: %v", err)
|
|
}
|
|
defer cli.Close()
|
|
|
|
// Create database and write data
|
|
db := cli.Database("testdb")
|
|
|
|
_, err = db.WriteOne("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)")
|
|
if err != nil {
|
|
t.Fatalf("Failed to create table: %v", err)
|
|
}
|
|
|
|
_, err = db.WriteOne("INSERT INTO users (name) VALUES ('Alice')")
|
|
if err != nil {
|
|
t.Fatalf("Failed to insert initial data: %v", err)
|
|
}
|
|
|
|
t.Log("Waiting for hibernation...")
|
|
time.Sleep(20 * time.Second)
|
|
|
|
t.Log("Attempting to wake up database by querying...")
|
|
|
|
// Query should trigger wake-up
|
|
startTime := time.Now()
|
|
rows, err := db.QueryOne("SELECT * FROM users")
|
|
wakeupDuration := time.Since(startTime)
|
|
|
|
if err != nil {
|
|
t.Fatalf("Failed to query after hibernation (wake-up failed): %v", err)
|
|
}
|
|
|
|
t.Logf("Wake-up took %v", wakeupDuration)
|
|
|
|
// Verify data persisted
|
|
if !rows.Next() {
|
|
t.Fatal("Expected at least one row after wake-up")
|
|
}
|
|
|
|
var id int
|
|
var name string
|
|
if err := rows.Scan(&id, &name); err != nil {
|
|
t.Fatalf("Failed to scan row: %v", err)
|
|
}
|
|
|
|
if name != "Alice" {
|
|
t.Errorf("Expected name 'Alice' after wake-up, got '%s'", name)
|
|
}
|
|
|
|
// Verify we can write new data
|
|
_, err = db.WriteOne("INSERT INTO users (name) VALUES ('Bob')")
|
|
if err != nil {
|
|
t.Fatalf("Failed to insert data after wake-up: %v", err)
|
|
}
|
|
|
|
// Verify both records exist
|
|
rows, err = db.QueryOne("SELECT COUNT(*) FROM users")
|
|
if err != nil {
|
|
t.Fatalf("Failed to count rows: %v", err)
|
|
}
|
|
|
|
if !rows.Next() {
|
|
t.Fatal("Expected count result")
|
|
}
|
|
|
|
var count int
|
|
if err := rows.Scan(&count); err != nil {
|
|
t.Fatalf("Failed to scan count: %v", err)
|
|
}
|
|
|
|
if count != 2 {
|
|
t.Errorf("Expected 2 rows after wake-up and insert, got %d", count)
|
|
}
|
|
|
|
t.Log("Wake-up cycle test passed")
|
|
}
|
|
|
|
// TestConcurrentHibernation tests multiple databases hibernating simultaneously
|
|
func TestConcurrentHibernation(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("Skipping e2e test in short mode")
|
|
}
|
|
|
|
// Setup test environment
|
|
testDir := filepath.Join(os.TempDir(), fmt.Sprintf("debros_test_concurrent_hibernate_%d", time.Now().Unix()))
|
|
defer os.RemoveAll(testDir)
|
|
|
|
logger, _ := zap.NewDevelopment()
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
|
defer cancel()
|
|
|
|
// Start 3 nodes
|
|
nodes := make([]*node.Node, 3)
|
|
for i := 0; i < 3; i++ {
|
|
cfg := config.DefaultConfig()
|
|
cfg.Node.DataDir = filepath.Join(testDir, fmt.Sprintf("node%d", i+1))
|
|
cfg.P2P.ListenAddresses = []string{fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", 14001+i)}
|
|
cfg.Database.ReplicationFactor = 3
|
|
cfg.Database.MaxDatabases = 20
|
|
cfg.Database.HibernationTimeout = 10 * time.Second
|
|
cfg.Database.PortRangeHTTPStart = 15001 + (i * 200)
|
|
cfg.Database.PortRangeHTTPEnd = 15050 + (i * 200)
|
|
cfg.Database.PortRangeRaftStart = 17001 + (i * 200)
|
|
cfg.Database.PortRangeRaftEnd = 17050 + (i * 200)
|
|
|
|
if i > 0 {
|
|
bootstrapAddr := nodes[0].Host().Addrs()[0].String() + "/p2p/" + nodes[0].Host().ID().String()
|
|
cfg.P2P.BootstrapPeers = []string{bootstrapAddr}
|
|
}
|
|
|
|
n, err := node.NewNode(cfg, logger)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create node %d: %v", i+1, err)
|
|
}
|
|
|
|
if err := n.Start(ctx); err != nil {
|
|
t.Fatalf("Failed to start node %d: %v", i+1, err)
|
|
}
|
|
defer n.Stop()
|
|
|
|
nodes[i] = n
|
|
}
|
|
|
|
time.Sleep(5 * time.Second)
|
|
|
|
// Create client
|
|
bootstrapAddr := nodes[0].Host().Addrs()[0].String() + "/p2p/" + nodes[0].Host().ID().String()
|
|
cli, err := client.NewClient(ctx, client.ClientConfig{
|
|
AppName: "testapp",
|
|
BootstrapPeers: []string{bootstrapAddr},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Failed to create client: %v", err)
|
|
}
|
|
defer cli.Close()
|
|
|
|
// Create multiple databases
|
|
dbNames := []string{"db1", "db2", "db3"}
|
|
for _, dbName := range dbNames {
|
|
db := cli.Database(dbName)
|
|
_, err = db.WriteOne(fmt.Sprintf("CREATE TABLE %s_data (id INTEGER PRIMARY KEY, value TEXT)", dbName))
|
|
if err != nil {
|
|
t.Fatalf("Failed to create table in %s: %v", dbName, err)
|
|
}
|
|
|
|
_, err = db.WriteOne(fmt.Sprintf("INSERT INTO %s_data (value) VALUES ('%s_value')", dbName, dbName))
|
|
if err != nil {
|
|
t.Fatalf("Failed to insert data in %s: %v", dbName, err)
|
|
}
|
|
}
|
|
|
|
t.Log("All databases created, waiting for concurrent hibernation...")
|
|
time.Sleep(20 * time.Second)
|
|
|
|
t.Log("Hibernation period elapsed")
|
|
|
|
// Verify all data directories still exist
|
|
for _, dbName := range dbNames {
|
|
for i := 0; i < 3; i++ {
|
|
dbDir := filepath.Join(testDir, fmt.Sprintf("node%d/testapp_%s", i+1, dbName))
|
|
if _, err := os.Stat(dbDir); os.IsNotExist(err) {
|
|
t.Errorf("Expected database directory for %s to exist on node %d", dbName, i+1)
|
|
}
|
|
}
|
|
}
|
|
|
|
t.Log("Concurrent hibernation test passed")
|
|
}
|