- 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.4 KiB
Go
139 lines
3.4 KiB
Go
package controllers
|
|
|
|
import (
|
|
"apiserver/models"
|
|
"apiserver/store"
|
|
"apiserver/utils"
|
|
"sync"
|
|
"testing"
|
|
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
func resetQueueControlState() {
|
|
store.InitStores()
|
|
utils.Log = zap.NewNop()
|
|
}
|
|
|
|
// TestPreCheckQueueControlRequest_AllFlag verifies that when queue_name is
|
|
// ["all"], the returned bool is true.
|
|
func TestPreCheckQueueControlRequest_AllFlag(t *testing.T) {
|
|
resetQueueControlState()
|
|
|
|
req := &models.QueueControlRequest{
|
|
ControlAction: "close",
|
|
QueueName: []string{"all"},
|
|
}
|
|
|
|
allFlag, err := preCheckQueueControlRequest(req)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if !allFlag {
|
|
t.Error("expected allFlag=true when queue_name is [\"all\"]")
|
|
}
|
|
}
|
|
|
|
// TestPreCheckQueueControlRequest_NotAll verifies that when queue_name is a
|
|
// specific queue, the returned bool is false.
|
|
func TestPreCheckQueueControlRequest_NotAll(t *testing.T) {
|
|
resetQueueControlState()
|
|
|
|
req := &models.QueueControlRequest{
|
|
ControlAction: "open",
|
|
QueueName: []string{"normal"},
|
|
}
|
|
|
|
allFlag, err := preCheckQueueControlRequest(req)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if allFlag {
|
|
t.Error("expected allFlag=false when queue_name is [\"normal\"]")
|
|
}
|
|
}
|
|
|
|
// TestPreCheckQueueControlRequest_NoRace verifies that concurrent calls to
|
|
// preCheckQueueControlRequest do not share state via a package-level variable.
|
|
func TestPreCheckQueueControlRequest_NoRace(t *testing.T) {
|
|
t.Parallel()
|
|
resetQueueControlState()
|
|
|
|
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.QueueControlRequest
|
|
if idx%2 == 0 {
|
|
req = models.QueueControlRequest{
|
|
ControlAction: "close",
|
|
QueueName: []string{"all"},
|
|
}
|
|
} else {
|
|
req = models.QueueControlRequest{
|
|
ControlAction: "open",
|
|
QueueName: []string{"normal"},
|
|
}
|
|
}
|
|
results[idx], errors[idx] = preCheckQueueControlRequest(&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 [\"normal\"]", i)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestPreCheckQueueControlRequest_InvalidAction verifies that an unsupported
|
|
// action returns an error.
|
|
func TestPreCheckQueueControlRequest_InvalidAction(t *testing.T) {
|
|
resetQueueControlState()
|
|
|
|
req := &models.QueueControlRequest{
|
|
ControlAction: "invalid_action",
|
|
QueueName: []string{"normal"},
|
|
}
|
|
|
|
_, err := preCheckQueueControlRequest(req)
|
|
if err == nil {
|
|
t.Error("expected error for invalid action, got nil")
|
|
}
|
|
}
|
|
|
|
// TestPreCheckQueueControlRequest_CommentTooLong verifies that a comment
|
|
// exceeding 512 characters returns an error.
|
|
func TestPreCheckQueueControlRequest_CommentTooLong(t *testing.T) {
|
|
resetQueueControlState()
|
|
|
|
longComment := make([]byte, 513)
|
|
for i := range longComment {
|
|
longComment[i] = 'a'
|
|
}
|
|
|
|
req := &models.QueueControlRequest{
|
|
ControlAction: "close",
|
|
QueueName: []string{"normal"},
|
|
Comment: string(longComment),
|
|
}
|
|
|
|
_, err := preCheckQueueControlRequest(req)
|
|
if err == nil {
|
|
t.Error("expected error for comment exceeding 512 chars, got nil")
|
|
}
|
|
}
|