fix(master): refuse jobs for revoked agents, signal revoked jobs, agent start time wins (#7)

This commit is contained in:
2026-10-12 19:14:32 +02:00
parent 93ba6915b9
commit c09e774d74
6 changed files with 138 additions and 57 deletions
+14 -12
View File
@@ -27,12 +27,13 @@ import (
// fakeStore is written from the HTTP handler goroutine and read by the test
// goroutine, so every access goes through mu.
type fakeStore struct {
mu sync.Mutex
services []model.Service
jobs []model.Job
agents []model.Agent
created map[string]string // name → token hash
revokedID int64
mu sync.Mutex
services []model.Service
jobs []model.Job
agents []model.Agent
created map[string]string // name → token hash
revokedID int64
revokeFailed []int64 // job IDs RevokeAgent reports as failed
}
func (f *fakeStore) ListServices(context.Context) ([]model.Service, error) { return f.services, nil }
@@ -76,11 +77,11 @@ func (f *fakeStore) CreateAgent(_ context.Context, name, hash string) (model.Age
return model.Agent{ID: 9, Name: name}, nil
}
func (f *fakeStore) RevokeAgent(_ context.Context, id int64, _ time.Time) error {
func (f *fakeStore) RevokeAgent(_ context.Context, id int64, _ time.Time) ([]int64, error) {
f.mu.Lock()
defer f.mu.Unlock()
f.revokedID = id
return nil
return f.revokeFailed, nil
}
func (f *fakeStore) createdHash(name string) string {
@@ -276,6 +277,7 @@ func TestCreateAgent_Validation(t *testing.T) {
func TestRevokeAgent_RevokesAndDisconnects(t *testing.T) {
srv, store, hub, broker := newTestServer(t)
store.revokeFailed = []int64{5, 6}
ch, cancel := broker.Subscribe()
defer cancel()
resp, err := noRedirectClient().Post(srv.URL+"/agents/2/revoke", "application/x-www-form-urlencoded", nil)
@@ -287,16 +289,16 @@ func TestRevokeAgent_RevokesAndDisconnects(t *testing.T) {
assert.Equal(t, int64(2), store.revoked())
assert.Equal(t, int64(2), hub.lastDisconnected(), "a revoked agent must be cut off immediately")
var got []events.Topic
for len(got) < 2 {
for len(got) < 4 {
select {
case topic := <-ch:
got = append(got, topic)
default:
t.Fatalf("revoke published %v, want services and jobs", got)
t.Fatalf("revoke published %v, want services, jobs and one topic per failed job", got)
}
}
assert.ElementsMatch(t, []events.Topic{events.Services, events.Jobs}, got,
"the overview drops the agent's services and job lists show its failed jobs")
assert.ElementsMatch(t, []events.Topic{events.Services, events.Jobs, events.JobTopic(5), events.JobTopic(6)}, got,
"the overview drops the agent's services; job lists and open job pages show the failures")
}
func TestRevokeAgent_BadID(t *testing.T) {