203 lines
3.7 KiB
Go
203 lines
3.7 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
package nomad
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/hashicorp/nomad/ci"
|
|
"github.com/hashicorp/nomad/nomad/mock"
|
|
"github.com/hashicorp/nomad/nomad/structs"
|
|
)
|
|
|
|
func testPlanQueue(t *testing.T) *PlanQueue {
|
|
pq, err := NewPlanQueue()
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
return pq
|
|
}
|
|
|
|
func TestPlanQueue_Enqueue_Dequeue(t *testing.T) {
|
|
ci.Parallel(t)
|
|
pq := testPlanQueue(t)
|
|
if pq.Enabled() {
|
|
t.Fatalf("should not be enabled")
|
|
}
|
|
pq.SetEnabled(true)
|
|
if !pq.Enabled() {
|
|
t.Fatalf("should be enabled")
|
|
}
|
|
|
|
plan := mock.Plan()
|
|
future, err := pq.Enqueue(plan)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
stats := pq.Stats()
|
|
if stats.Depth != 1 {
|
|
t.Fatalf("bad: %#v", stats)
|
|
}
|
|
|
|
resCh := make(chan *structs.PlanResult, 1)
|
|
errCh := make(chan error)
|
|
go func() {
|
|
defer close(errCh)
|
|
defer close(resCh)
|
|
|
|
res, err := future.Wait()
|
|
if err != nil {
|
|
errCh <- err
|
|
return
|
|
}
|
|
resCh <- res
|
|
}()
|
|
|
|
pending, err := pq.Dequeue(time.Second)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
stats = pq.Stats()
|
|
if stats.Depth != 0 {
|
|
t.Fatalf("bad: %#v", stats)
|
|
}
|
|
|
|
if pending == nil || pending.plan != plan {
|
|
t.Fatalf("bad: %#v", pending)
|
|
}
|
|
|
|
result := mock.PlanResult()
|
|
pending.respond(result, nil)
|
|
|
|
select {
|
|
case err := <-errCh:
|
|
if err != nil {
|
|
t.Fatalf("error in anonymous goroutine: %s", err)
|
|
}
|
|
case r := <-resCh:
|
|
if r != result {
|
|
t.Fatalf("Bad: %#v", r)
|
|
}
|
|
case <-time.After(time.Second):
|
|
t.Fatalf("timeout")
|
|
}
|
|
}
|
|
|
|
func TestPlanQueue_Enqueue_Disable(t *testing.T) {
|
|
ci.Parallel(t)
|
|
pq := testPlanQueue(t)
|
|
|
|
// Enqueue
|
|
plan := mock.Plan()
|
|
pq.SetEnabled(true)
|
|
future, err := pq.Enqueue(plan)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
// Flush via SetEnabled
|
|
pq.SetEnabled(false)
|
|
|
|
// Check the stats
|
|
stats := pq.Stats()
|
|
if stats.Depth != 0 {
|
|
t.Fatalf("bad: %#v", stats)
|
|
}
|
|
|
|
// Future should be canceled
|
|
res, err := future.Wait()
|
|
if err != planQueueFlushed {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if res != nil {
|
|
t.Fatalf("bad: %#v", res)
|
|
}
|
|
}
|
|
|
|
func TestPlanQueue_Dequeue_Timeout(t *testing.T) {
|
|
ci.Parallel(t)
|
|
pq := testPlanQueue(t)
|
|
pq.SetEnabled(true)
|
|
|
|
start := time.Now()
|
|
out, err := pq.Dequeue(5 * time.Millisecond)
|
|
end := time.Now()
|
|
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
if out != nil {
|
|
t.Fatalf("unexpected: %#v", out)
|
|
}
|
|
|
|
if diff := end.Sub(start); diff < 5*time.Millisecond {
|
|
t.Fatalf("bad: %#v", diff)
|
|
}
|
|
}
|
|
|
|
// Ensure higher priority dequeued first
|
|
func TestPlanQueue_Dequeue_Priority(t *testing.T) {
|
|
ci.Parallel(t)
|
|
pq := testPlanQueue(t)
|
|
pq.SetEnabled(true)
|
|
|
|
plan1 := mock.Plan()
|
|
plan1.Priority = 10
|
|
pq.Enqueue(plan1)
|
|
|
|
plan2 := mock.Plan()
|
|
plan2.Priority = 30
|
|
pq.Enqueue(plan2)
|
|
|
|
plan3 := mock.Plan()
|
|
plan3.Priority = 20
|
|
pq.Enqueue(plan3)
|
|
|
|
out1, _ := pq.Dequeue(time.Second)
|
|
if out1.plan != plan2 {
|
|
t.Fatalf("bad: %#v", out1)
|
|
}
|
|
|
|
out2, _ := pq.Dequeue(time.Second)
|
|
if out2.plan != plan3 {
|
|
t.Fatalf("bad: %#v", out2)
|
|
}
|
|
|
|
out3, _ := pq.Dequeue(time.Second)
|
|
if out3.plan != plan1 {
|
|
t.Fatalf("bad: %#v", out3)
|
|
}
|
|
}
|
|
|
|
// Ensure FIFO at fixed priority
|
|
func TestPlanQueue_Dequeue_FIFO(t *testing.T) {
|
|
ci.Parallel(t)
|
|
pq := testPlanQueue(t)
|
|
pq.SetEnabled(true)
|
|
|
|
plans := make([]*structs.Plan, 100)
|
|
for i := 0; i < len(plans); i++ {
|
|
if i%5 == 0 {
|
|
time.Sleep(10 * time.Millisecond)
|
|
}
|
|
plans[i] = mock.Plan()
|
|
pq.Enqueue(plans[i])
|
|
}
|
|
|
|
var prev *pendingPlan
|
|
for i := range plans {
|
|
out, err := pq.Dequeue(time.Second)
|
|
if err != nil {
|
|
t.Fatalf("failed to dequeue plan %d: %v", i, err)
|
|
}
|
|
if prev != nil && out.enqueueTime.Before(prev.enqueueTime) {
|
|
t.Fatalf("out of order dequeue at %d, prev=%v, got=%v", i, prev.enqueueTime, out.enqueueTime)
|
|
}
|
|
prev = out
|
|
}
|
|
}
|