Add web auth, infinite-scroll, agent admission and review fixes across agent/server/web
This commit is contained in:
@@ -2,6 +2,7 @@ package scheduler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -9,6 +10,14 @@ import (
|
||||
"github.com/monlet/agent/internal/config"
|
||||
)
|
||||
|
||||
func runScheduler(ctx context.Context, agentID string, checks []config.CheckConfig, out chan<- Event, h Hooks) {
|
||||
m := NewManager(ctx, agentID, out, h)
|
||||
m.Update(checks)
|
||||
<-ctx.Done()
|
||||
m.Stop()
|
||||
m.Wait()
|
||||
}
|
||||
|
||||
func mkCheck(id, cmd string, interval, timeout time.Duration) config.CheckConfig {
|
||||
return config.CheckConfig{
|
||||
ID: id,
|
||||
@@ -22,7 +31,7 @@ func TestEmitsEvents(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
|
||||
defer cancel()
|
||||
out := make(chan Event, 10)
|
||||
go Run(ctx, "a1", []config.CheckConfig{mkCheck("c1", "echo hi", 200*time.Millisecond, 100*time.Millisecond)}, out, Hooks{})
|
||||
go runScheduler(ctx, "a1", []config.CheckConfig{mkCheck("c1", "echo hi", 200*time.Millisecond, 100*time.Millisecond)}, out, Hooks{})
|
||||
select {
|
||||
case ev := <-out:
|
||||
if ev.CheckID != "c1" || ev.Status != "ok" {
|
||||
@@ -43,9 +52,168 @@ func TestNoOverlapSkips(t *testing.T) {
|
||||
var skipped int32
|
||||
hooks := Hooks{OnSkipped: func(string) { atomic.AddInt32(&skipped, 1) }}
|
||||
c := mkCheck("slow", "sleep 1", 100*time.Millisecond, 900*time.Millisecond)
|
||||
go Run(ctx, "a1", []config.CheckConfig{c}, out, hooks)
|
||||
go runScheduler(ctx, "a1", []config.CheckConfig{c}, out, hooks)
|
||||
<-ctx.Done()
|
||||
if atomic.LoadInt32(&skipped) == 0 {
|
||||
t.Fatal("expected at least one skipped tick")
|
||||
}
|
||||
}
|
||||
|
||||
func TestReportsFullEventChannel(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel()
|
||||
out := make(chan Event, 1)
|
||||
out <- Event{EventID: "occupied"}
|
||||
var full int32
|
||||
m := NewManager(ctx, "a1", out, Hooks{
|
||||
OnEventChannelFull: func() { atomic.AddInt32(&full, 1) },
|
||||
})
|
||||
m.Update([]config.CheckConfig{mkCheck("c1", "echo hi", time.Hour, time.Second)})
|
||||
|
||||
deadline := time.Now().Add(time.Second)
|
||||
for time.Now().Before(deadline) {
|
||||
if atomic.LoadInt32(&full) > 0 {
|
||||
break
|
||||
}
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
if atomic.LoadInt32(&full) == 0 {
|
||||
t.Fatal("expected full channel hook")
|
||||
}
|
||||
<-out
|
||||
select {
|
||||
case ev := <-out:
|
||||
if ev.CheckID != "c1" {
|
||||
t.Fatalf("unexpected event: %+v", ev)
|
||||
}
|
||||
case <-ctx.Done():
|
||||
t.Fatal("blocked event was not delivered")
|
||||
}
|
||||
m.Stop()
|
||||
m.Wait()
|
||||
}
|
||||
|
||||
func TestManagerReloadChangedCheckWaitsForRunning(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel()
|
||||
out := make(chan Event, 10)
|
||||
m := NewManager(ctx, "a1", out, Hooks{})
|
||||
m.Update([]config.CheckConfig{mkCheck("c1", "sleep 0.3; echo old", time.Second, time.Second)})
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
m.Update([]config.CheckConfig{mkCheck("c1", "echo new", time.Second, time.Second)})
|
||||
|
||||
var first, second Event
|
||||
select {
|
||||
case first = <-out:
|
||||
case <-ctx.Done():
|
||||
t.Fatal("no first event")
|
||||
}
|
||||
select {
|
||||
case second = <-out:
|
||||
case <-ctx.Done():
|
||||
t.Fatal("no second event")
|
||||
}
|
||||
m.Stop()
|
||||
m.Wait()
|
||||
|
||||
if !strings.Contains(first.Output, "old") {
|
||||
t.Fatalf("first output: %q", first.Output)
|
||||
}
|
||||
if !strings.Contains(second.Output, "new") {
|
||||
t.Fatalf("second output: %q", second.Output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestManagerReloadRemovedCheckLetsRunningFinish(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel()
|
||||
out := make(chan Event, 10)
|
||||
stopped := make(chan string, 1)
|
||||
m := NewManager(ctx, "a1", out, Hooks{OnStopped: func(id string) { stopped <- id }})
|
||||
m.Update([]config.CheckConfig{mkCheck("c1", "sleep 0.2; echo old", time.Second, time.Second)})
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
m.Update(nil)
|
||||
|
||||
select {
|
||||
case ev := <-out:
|
||||
if !strings.Contains(ev.Output, "old") {
|
||||
t.Fatalf("output: %q", ev.Output)
|
||||
}
|
||||
case <-ctx.Done():
|
||||
t.Fatal("removed running check did not finish")
|
||||
}
|
||||
select {
|
||||
case id := <-stopped:
|
||||
if id != "c1" {
|
||||
t.Fatalf("stopped id: %q", id)
|
||||
}
|
||||
case <-ctx.Done():
|
||||
t.Fatal("removed check did not stop")
|
||||
}
|
||||
m.Stop()
|
||||
m.Wait()
|
||||
}
|
||||
|
||||
func TestManagerRemoveThenReaddSameCheckDoesNotOverlap(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
defer cancel()
|
||||
out := make(chan Event, 10)
|
||||
m := NewManager(ctx, "a1", out, Hooks{})
|
||||
m.Update([]config.CheckConfig{mkCheck("c1", "sleep 0.25; echo old", time.Second, time.Second)})
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
m.Update(nil)
|
||||
m.Update([]config.CheckConfig{mkCheck("c1", "echo new", time.Second, time.Second)})
|
||||
|
||||
var first, second Event
|
||||
select {
|
||||
case first = <-out:
|
||||
case <-ctx.Done():
|
||||
t.Fatal("no first event")
|
||||
}
|
||||
select {
|
||||
case second = <-out:
|
||||
case <-ctx.Done():
|
||||
t.Fatal("no second event")
|
||||
}
|
||||
m.Stop()
|
||||
m.Wait()
|
||||
|
||||
if !strings.Contains(first.Output, "old") {
|
||||
t.Fatalf("first output: %q", first.Output)
|
||||
}
|
||||
if !strings.Contains(second.Output, "new") {
|
||||
t.Fatalf("second output: %q", second.Output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestManagerUsesLatestPendingReloadAfterRunningFinishes(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
defer cancel()
|
||||
out := make(chan Event, 10)
|
||||
m := NewManager(ctx, "a1", out, Hooks{})
|
||||
m.Update([]config.CheckConfig{mkCheck("c1", "sleep 0.25; echo old", time.Second, time.Second)})
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
m.Update([]config.CheckConfig{mkCheck("c1", "echo intermediate", time.Second, time.Second)})
|
||||
m.Update([]config.CheckConfig{mkCheck("c1", "echo latest", time.Second, time.Second)})
|
||||
|
||||
var first, second Event
|
||||
select {
|
||||
case first = <-out:
|
||||
case <-ctx.Done():
|
||||
t.Fatal("no first event")
|
||||
}
|
||||
select {
|
||||
case second = <-out:
|
||||
case <-ctx.Done():
|
||||
t.Fatal("no second event")
|
||||
}
|
||||
m.Stop()
|
||||
m.Wait()
|
||||
|
||||
if !strings.Contains(first.Output, "old") {
|
||||
t.Fatalf("first output: %q", first.Output)
|
||||
}
|
||||
if strings.Contains(second.Output, "intermediate") || !strings.Contains(second.Output, "latest") {
|
||||
t.Fatalf("second output: %q", second.Output)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user