Files
2026-07-30 12:23:05 +08:00

79 lines
2.3 KiB
Go

package api
import (
"net/http"
"net/http/httptest"
"strings"
"sync"
"testing"
"github.com/gin-gonic/gin"
)
func countLifecycleWinners(instanceID string, workers int) int {
start := make(chan struct{})
results := make(chan bool, workers)
var wg sync.WaitGroup
for range workers {
wg.Add(1)
go func() {
defer wg.Done()
<-start
results <- beginInstanceLifecycleOperation(instanceID)
}()
}
close(start)
wg.Wait()
close(results)
winners := 0
for won := range results {
if won {
winners++
}
}
return winners
}
func TestBeginInstanceLifecycleOperationSingleFlight(t *testing.T) {
instanceID := "ocid1.instance.oc1..single-flight"
instanceLifecycleGuard.Delete(instanceID)
t.Cleanup(func() { instanceLifecycleGuard.Delete(instanceID) })
if got, want := countLifecycleWinners(instanceID, 16), 1; got != want {
t.Errorf("winners = %d, want %d", got, want)
}
}
func instanceOperationRouter() *gin.Engine {
h := &ociConfigHandler{}
r := gin.New()
r.DELETE("/oci-configs/:id/instances/:instanceId", h.terminateInstance)
r.POST("/oci-configs/:id/instances/:instanceId/action", h.instanceAction)
return r
}
func TestInstanceLifecycleOperationRejectsLaterRequest(t *testing.T) {
gin.SetMode(gin.TestMode)
instanceID := "ocid1.instance.oc1..same-physical-instance"
instanceLifecycleGuard.Store(instanceID, struct{}{})
t.Cleanup(func() { instanceLifecycleGuard.Delete(instanceID) })
r := instanceOperationRouter()
tests := []struct {
name, method, path, body string
}{
{"action先占位时跨配置terminate被拒", http.MethodDelete, "/oci-configs/2/instances/" + instanceID, ""},
{"terminate先占位时action被拒", http.MethodPost, "/oci-configs/1/instances/" + instanceID + "/action", `{"action":"STOP"}`},
{"action先占位时第二个action被拒", http.MethodPost, "/oci-configs/3/instances/" + instanceID + "/action", `{"action":"RESET"}`},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req := httptest.NewRequest(tt.method, tt.path, strings.NewReader(tt.body))
req.Header.Set("Content-Type", "application/json")
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
if got, want := w.Code, http.StatusConflict; got != want {
t.Errorf("status = %d, want %d, body %s", got, want, w.Body.String())
}
})
}
}