- backend/clib.go: Replace ControlHost stub with real implementation using xcecli_hostctrl, following the same pattern as ControlQueue - controllers/hosts.go: Remove package-level allFlag variable; preCheckHostControlRequest now returns (bool, error) so the allFlag is a local value in the caller, eliminating the data race - controllers/queues.go: Same fix for preCheckQueueControlRequest - Add unit tests for both preCheck functions verifying return values, error cases, and concurrent safety - Add compile-time verification test for ControlHost stub signature
139 lines
3.3 KiB
Go
139 lines
3.3 KiB
Go
package controllers
|
|
|
|
import (
|
|
"apiserver/models"
|
|
"apiserver/store"
|
|
"apiserver/utils"
|
|
"sync"
|
|
"testing"
|
|
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
func resetHostControlState() {
|
|
store.InitStores()
|
|
utils.Log = zap.NewNop()
|
|
}
|
|
|
|
// TestPreCheckHostControlRequest_AllFlag verifies that when hostname is ["all"],
|
|
// the returned bool is true.
|
|
func TestPreCheckHostControlRequest_AllFlag(t *testing.T) {
|
|
resetHostControlState()
|
|
|
|
req := &models.HostControlRequest{
|
|
ControlAction: "close",
|
|
Hostname: []string{"all"},
|
|
}
|
|
|
|
allFlag, err := preCheckHostControlRequest(req)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if !allFlag {
|
|
t.Error("expected allFlag=true when hostname is [\"all\"]")
|
|
}
|
|
}
|
|
|
|
// TestPreCheckHostControlRequest_NotAll verifies that when hostname is a
|
|
// specific host, the returned bool is false.
|
|
func TestPreCheckHostControlRequest_NotAll(t *testing.T) {
|
|
resetHostControlState()
|
|
|
|
req := &models.HostControlRequest{
|
|
ControlAction: "open",
|
|
Hostname: []string{"node01"},
|
|
}
|
|
|
|
allFlag, err := preCheckHostControlRequest(req)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if allFlag {
|
|
t.Error("expected allFlag=false when hostname is [\"node01\"]")
|
|
}
|
|
}
|
|
|
|
// TestPreCheckHostControlRequest_NoRace verifies that concurrent calls to
|
|
// preCheckHostControlRequest do not share state via a package-level variable.
|
|
func TestPreCheckHostControlRequest_NoRace(t *testing.T) {
|
|
t.Parallel()
|
|
resetHostControlState()
|
|
|
|
var wg sync.WaitGroup
|
|
const goroutines = 50
|
|
|
|
results := make([]bool, goroutines)
|
|
errors := make([]error, goroutines)
|
|
|
|
for i := 0; i < goroutines; i++ {
|
|
wg.Add(1)
|
|
go func(idx int) {
|
|
defer wg.Done()
|
|
var req models.HostControlRequest
|
|
if idx%2 == 0 {
|
|
req = models.HostControlRequest{
|
|
ControlAction: "close",
|
|
Hostname: []string{"all"},
|
|
}
|
|
} else {
|
|
req = models.HostControlRequest{
|
|
ControlAction: "open",
|
|
Hostname: []string{"node01"},
|
|
}
|
|
}
|
|
results[idx], errors[idx] = preCheckHostControlRequest(&req)
|
|
}(i)
|
|
}
|
|
wg.Wait()
|
|
|
|
for i := 0; i < goroutines; i++ {
|
|
if errors[i] != nil {
|
|
t.Errorf("goroutine %d: unexpected error: %v", i, errors[i])
|
|
continue
|
|
}
|
|
if i%2 == 0 && !results[i] {
|
|
t.Errorf("goroutine %d: expected allFlag=true for [\"all\"]", i)
|
|
}
|
|
if i%2 != 0 && results[i] {
|
|
t.Errorf("goroutine %d: expected allFlag=false for [\"node01\"]", i)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestPreCheckHostControlRequest_InvalidAction verifies that an unsupported
|
|
// action returns an error.
|
|
func TestPreCheckHostControlRequest_InvalidAction(t *testing.T) {
|
|
resetHostControlState()
|
|
|
|
req := &models.HostControlRequest{
|
|
ControlAction: "invalid_action",
|
|
Hostname: []string{"node01"},
|
|
}
|
|
|
|
_, err := preCheckHostControlRequest(req)
|
|
if err == nil {
|
|
t.Error("expected error for invalid action, got nil")
|
|
}
|
|
}
|
|
|
|
// TestPreCheckHostControlRequest_CommentTooLong verifies that a comment
|
|
// exceeding 512 characters returns an error.
|
|
func TestPreCheckHostControlRequest_CommentTooLong(t *testing.T) {
|
|
resetHostControlState()
|
|
|
|
longComment := make([]byte, 513)
|
|
for i := range longComment {
|
|
longComment[i] = 'a'
|
|
}
|
|
|
|
req := &models.HostControlRequest{
|
|
ControlAction: "close",
|
|
Hostname: []string{"node01"},
|
|
Comment: string(longComment),
|
|
}
|
|
|
|
_, err := preCheckHostControlRequest(req)
|
|
if err == nil {
|
|
t.Error("expected error for comment exceeding 512 chars, got nil")
|
|
}
|
|
}
|