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