You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

434 lines
12 KiB

package task
import (
"fmt"
"testing"
"time"
"github.com/seaweedfs/seaweedfs/weed/worker/types"
)
// TestMinimalIntegration tests basic admin-worker operational flow using the minimal implementation
func TestMinimalIntegration(t *testing.T) {
t.Logf("Starting minimal integration test")
// Step 1: Create a minimal admin server configuration
config := &MinimalAdminConfig{
ScanInterval: 10 * time.Second,
WorkerTimeout: 30 * time.Second,
TaskTimeout: 2 * time.Hour,
MaxRetries: 3,
ReconcileInterval: 5 * time.Minute,
EnableFailureRecovery: true,
MaxConcurrentTasks: 5,
}
// Step 2: Create minimal admin server with nil master client (for testing)
adminServer := NewMinimalAdminServer(config, nil)
// Step 3: Start admin server
err := adminServer.Start()
if err != nil {
t.Fatalf("Failed to start admin server: %v", err)
}
defer adminServer.Stop()
// Step 4: Test worker registration
t.Logf("Testing worker registration")
worker := &types.Worker{
ID: "test-worker-1",
Address: "localhost:9001",
Capabilities: []types.TaskType{types.TaskTypeVacuum},
MaxConcurrent: 2,
Status: "active",
CurrentLoad: 0,
LastHeartbeat: time.Now(),
}
err = adminServer.RegisterWorker(worker)
if err != nil {
t.Fatalf("Failed to register worker: %v", err)
}
t.Logf("Successfully registered worker %s", worker.ID)
// Step 5: Test task queueing
t.Logf("Testing task queueing")
task := &types.Task{
ID: "test-task-1",
Type: types.TaskTypeVacuum,
VolumeID: 1001,
Server: "localhost:8080",
Status: types.TaskStatusPending,
Priority: types.TaskPriorityNormal,
Parameters: map[string]interface{}{
"garbage_threshold": "0.3",
},
CreatedAt: time.Now(),
}
err = adminServer.QueueTask(task)
if err != nil {
t.Fatalf("Failed to queue task: %v", err)
}
t.Logf("Successfully queued task %s", task.ID)
// Step 6: Test task request by worker
t.Logf("Testing task request")
assignedTask, err := adminServer.RequestTask("test-worker-1", []types.TaskType{types.TaskTypeVacuum})
if err != nil {
t.Fatalf("Failed to request task: %v", err)
}
if assignedTask != nil {
t.Logf("Successfully assigned task %s to worker", assignedTask.ID)
// Step 7: Test task progress updates
t.Logf("Testing task progress updates")
err = adminServer.UpdateTaskProgress(assignedTask.ID, 25.0)
if err != nil {
t.Errorf("Failed to update task progress to 25%%: %v", err)
}
err = adminServer.UpdateTaskProgress(assignedTask.ID, 50.0)
if err != nil {
t.Errorf("Failed to update task progress to 50%%: %v", err)
}
err = adminServer.UpdateTaskProgress(assignedTask.ID, 75.0)
if err != nil {
t.Errorf("Failed to update task progress to 75%%: %v", err)
}
err = adminServer.UpdateTaskProgress(assignedTask.ID, 100.0)
if err != nil {
t.Errorf("Failed to update task progress to 100%%: %v", err)
}
// Step 8: Test task completion
t.Logf("Testing task completion")
err = adminServer.CompleteTask(assignedTask.ID, true, "")
if err != nil {
t.Errorf("Failed to complete task: %v", err)
}
t.Logf("Successfully completed task %s", assignedTask.ID)
} else {
t.Logf("No task was assigned (queue might be empty)")
}
// Step 9: Test basic metrics
t.Logf("Testing basic metrics")
stats := adminServer.GetSystemStats()
if stats != nil {
t.Logf("System stats: Active tasks=%d, Queued tasks=%d, Active workers=%d, Total tasks=%d",
stats.ActiveTasks, stats.QueuedTasks, stats.ActiveWorkers, stats.TotalTasks)
}
queuedCount := adminServer.GetQueuedTaskCount()
activeCount := adminServer.GetActiveTaskCount()
t.Logf("Queue status: %d queued, %d active tasks", queuedCount, activeCount)
// Step 10: Test task history
history := adminServer.GetTaskHistory()
t.Logf("Task history contains %d entries", len(history))
if len(history) > 0 {
lastEntry := history[len(history)-1]
t.Logf("Last task in history: %s (%s) - Status: %s, Duration: %v",
lastEntry.TaskID, lastEntry.TaskType, lastEntry.Status, lastEntry.Duration)
}
t.Logf("Minimal integration test completed successfully")
}
// TestMinimalWorkerHeartbeat tests worker heartbeat functionality
func TestMinimalWorkerHeartbeat(t *testing.T) {
t.Logf("Testing minimal worker heartbeat")
config := &MinimalAdminConfig{
ScanInterval: 10 * time.Second,
WorkerTimeout: 30 * time.Second,
TaskTimeout: 2 * time.Hour,
MaxRetries: 3,
ReconcileInterval: 5 * time.Minute,
EnableFailureRecovery: true,
MaxConcurrentTasks: 5,
}
adminServer := NewMinimalAdminServer(config, nil)
err := adminServer.Start()
if err != nil {
t.Fatalf("Failed to start admin server: %v", err)
}
defer adminServer.Stop()
// Register a worker
worker := &types.Worker{
ID: "heartbeat-worker",
Address: "localhost:9002",
Capabilities: []types.TaskType{types.TaskTypeVacuum},
MaxConcurrent: 1,
Status: "active",
CurrentLoad: 0,
LastHeartbeat: time.Now(),
}
err = adminServer.RegisterWorker(worker)
if err != nil {
t.Fatalf("Failed to register worker: %v", err)
}
// Test heartbeat update
status := &types.WorkerStatus{
Status: "active",
CurrentLoad: 0,
}
err = adminServer.UpdateWorkerHeartbeat("heartbeat-worker", status)
if err != nil {
t.Errorf("Failed to update worker heartbeat: %v", err)
}
t.Logf("Minimal worker heartbeat test completed successfully")
}
// TestMinimalTaskQueueOperations tests task queue operations
func TestMinimalTaskQueueOperations(t *testing.T) {
t.Logf("Testing minimal task queue operations")
config := &MinimalAdminConfig{
ScanInterval: 10 * time.Second,
WorkerTimeout: 30 * time.Second,
TaskTimeout: 2 * time.Hour,
MaxRetries: 3,
ReconcileInterval: 5 * time.Minute,
EnableFailureRecovery: true,
MaxConcurrentTasks: 5,
}
adminServer := NewMinimalAdminServer(config, nil)
err := adminServer.Start()
if err != nil {
t.Fatalf("Failed to start admin server: %v", err)
}
defer adminServer.Stop()
// Test queuing multiple tasks
taskCount := 3
for i := 0; i < taskCount; i++ {
task := &types.Task{
ID: fmt.Sprintf("queue-test-task-%d", i),
Type: types.TaskTypeVacuum,
VolumeID: uint32(2000 + i),
Server: "localhost:8080",
Status: types.TaskStatusPending,
Priority: types.TaskPriorityNormal,
Parameters: map[string]interface{}{
"garbage_threshold": "0.3",
},
CreatedAt: time.Now(),
}
err = adminServer.QueueTask(task)
if err != nil {
t.Errorf("Failed to queue task %d: %v", i, err)
}
}
// Check queue size
queuedCount := adminServer.GetQueuedTaskCount()
if queuedCount != taskCount {
t.Errorf("Expected %d queued tasks, got %d", taskCount, queuedCount)
}
t.Logf("Minimal task queue operations test completed successfully")
}
// TestMinimalFullWorkflow tests the complete workflow from task creation to completion
func TestMinimalFullWorkflow(t *testing.T) {
t.Logf("Testing minimal full workflow")
config := &MinimalAdminConfig{
ScanInterval: 10 * time.Second,
WorkerTimeout: 30 * time.Second,
TaskTimeout: 2 * time.Hour,
MaxRetries: 3,
ReconcileInterval: 5 * time.Minute,
EnableFailureRecovery: true,
MaxConcurrentTasks: 5,
}
adminServer := NewMinimalAdminServer(config, nil)
err := adminServer.Start()
if err != nil {
t.Fatalf("Failed to start admin server: %v", err)
}
defer adminServer.Stop()
// Register multiple workers with different capabilities
workers := []*types.Worker{
{
ID: "vacuum-worker-1",
Address: "localhost:9001",
Capabilities: []types.TaskType{types.TaskTypeVacuum},
MaxConcurrent: 2,
Status: "active",
CurrentLoad: 0,
LastHeartbeat: time.Now(),
},
{
ID: "ec-worker-1",
Address: "localhost:9002",
Capabilities: []types.TaskType{types.TaskTypeErasureCoding},
MaxConcurrent: 1,
Status: "active",
CurrentLoad: 0,
LastHeartbeat: time.Now(),
},
{
ID: "multi-worker-1",
Address: "localhost:9003",
Capabilities: []types.TaskType{types.TaskTypeVacuum, types.TaskTypeErasureCoding},
MaxConcurrent: 3,
Status: "active",
CurrentLoad: 0,
LastHeartbeat: time.Now(),
},
}
for _, worker := range workers {
err = adminServer.RegisterWorker(worker)
if err != nil {
t.Fatalf("Failed to register worker %s: %v", worker.ID, err)
}
t.Logf("Registered worker %s with capabilities %v", worker.ID, worker.Capabilities)
}
// Create multiple tasks of different types
tasks := []*types.Task{
{
ID: "vacuum-task-1",
Type: types.TaskTypeVacuum,
VolumeID: 3001,
Server: "localhost:8080",
Status: types.TaskStatusPending,
Priority: types.TaskPriorityNormal,
Parameters: map[string]interface{}{
"garbage_threshold": "0.4",
},
CreatedAt: time.Now(),
},
{
ID: "ec-task-1",
Type: types.TaskTypeErasureCoding,
VolumeID: 3002,
Server: "localhost:8080",
Status: types.TaskStatusPending,
Priority: types.TaskPriorityHigh,
Parameters: map[string]interface{}{
"shard_count": "14",
},
CreatedAt: time.Now(),
},
{
ID: "vacuum-task-2",
Type: types.TaskTypeVacuum,
VolumeID: 3003,
Server: "localhost:8081",
Status: types.TaskStatusPending,
Priority: types.TaskPriorityLow,
Parameters: map[string]interface{}{
"garbage_threshold": "0.5",
},
CreatedAt: time.Now(),
},
}
for _, task := range tasks {
err = adminServer.QueueTask(task)
if err != nil {
t.Fatalf("Failed to queue task %s: %v", task.ID, err)
}
t.Logf("Queued task %s (%s) for volume %d", task.ID, task.Type, task.VolumeID)
}
// Test task assignment to different workers
t.Logf("Testing task assignments")
// Vacuum worker should get vacuum tasks
assignedTask, err := adminServer.RequestTask("vacuum-worker-1", []types.TaskType{types.TaskTypeVacuum})
if err != nil {
t.Errorf("Failed to request task for vacuum worker: %v", err)
} else if assignedTask != nil {
t.Logf("Vacuum worker got task: %s (%s)", assignedTask.ID, assignedTask.Type)
// Complete the task
err = adminServer.UpdateTaskProgress(assignedTask.ID, 50.0)
if err != nil {
t.Errorf("Failed to update progress: %v", err)
}
err = adminServer.CompleteTask(assignedTask.ID, true, "")
if err != nil {
t.Errorf("Failed to complete task: %v", err)
}
}
// EC worker should get EC tasks
assignedTask, err = adminServer.RequestTask("ec-worker-1", []types.TaskType{types.TaskTypeErasureCoding})
if err != nil {
t.Errorf("Failed to request task for EC worker: %v", err)
} else if assignedTask != nil {
t.Logf("EC worker got task: %s (%s)", assignedTask.ID, assignedTask.Type)
// Complete the task
err = adminServer.UpdateTaskProgress(assignedTask.ID, 100.0)
if err != nil {
t.Errorf("Failed to update progress: %v", err)
}
err = adminServer.CompleteTask(assignedTask.ID, true, "")
if err != nil {
t.Errorf("Failed to complete task: %v", err)
}
}
// Multi-capability worker should be able to get any remaining task
assignedTask, err = adminServer.RequestTask("multi-worker-1", []types.TaskType{types.TaskTypeVacuum, types.TaskTypeErasureCoding})
if err != nil {
t.Errorf("Failed to request task for multi worker: %v", err)
} else if assignedTask != nil {
t.Logf("Multi worker got task: %s (%s)", assignedTask.ID, assignedTask.Type)
// Complete the task
err = adminServer.UpdateTaskProgress(assignedTask.ID, 100.0)
if err != nil {
t.Errorf("Failed to update progress: %v", err)
}
err = adminServer.CompleteTask(assignedTask.ID, true, "")
if err != nil {
t.Errorf("Failed to complete task: %v", err)
}
}
// Check final statistics
stats := adminServer.GetSystemStats()
t.Logf("Final stats: Active tasks=%d, Queued tasks=%d, Active workers=%d, Total tasks=%d",
stats.ActiveTasks, stats.QueuedTasks, stats.ActiveWorkers, stats.TotalTasks)
history := adminServer.GetTaskHistory()
t.Logf("Task history contains %d completed tasks", len(history))
for _, entry := range history {
t.Logf("Completed: %s (%s) - Worker: %s, Duration: %v",
entry.TaskID, entry.TaskType, entry.WorkerID, entry.Duration)
}
t.Logf("Minimal full workflow test completed successfully")
}