88 lines
3.2 KiB
Go
88 lines
3.2 KiB
Go
package dispatcher
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"io"
|
|
"log/slog"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"git.ipao.vip/rogee/go-sip/internal/configread"
|
|
"git.ipao.vip/rogee/go-sip/internal/store"
|
|
)
|
|
|
|
func TestStartupAndSIPNotificationNeverLoadOverOccupiedOrUnknownCalls(t *testing.T) {
|
|
for _, outcome := range []string{"active", "unknown"} {
|
|
for _, phase := range []string{"startup", "notification"} {
|
|
t.Run(outcome+"/"+phase, func(t *testing.T) {
|
|
execute, originator, _, database := newExecuteFixture(t)
|
|
if outcome == "unknown" {
|
|
originator.err = context.DeadlineExceeded
|
|
}
|
|
err := execute.ProcessExecute(context.Background(), executeBody(t, "sip-load-occupied", "15003164745"))
|
|
if (outcome == "unknown") != (err != nil) {
|
|
t.Fatalf("unexpected isolated execution state: %v", err)
|
|
}
|
|
occupied, err := database.OccupiedCalls(execute.DispatcherID)
|
|
if err != nil || occupied != 1 {
|
|
t.Fatalf("occupied before update = %d, error = %v", occupied, err)
|
|
}
|
|
var snapshot configread.SIP
|
|
if err := json.Unmarshal(configExample(t, "config-read-sip"), &snapshot); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
snapshot.Revision = 9
|
|
body, err := json.Marshal(snapshot)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/internal/v1/dispatcher/sip" {
|
|
t.Errorf("occupied startup requested unrelated configuration: %s", r.URL.Path)
|
|
w.WriteHeader(http.StatusNotFound)
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
_, _ = w.Write(body)
|
|
}))
|
|
defer server.Close()
|
|
client, err := configread.NewClient(server.URL, execute.DispatcherID, "test-secret", server.Client())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
applied, verified := 0, 0
|
|
bootstrap := Bootstrap{
|
|
Client: client, Store: database, DispatcherID: execute.DispatcherID,
|
|
ApplySIP: func(context.Context, configread.SIP) error { applied++; return nil },
|
|
VerifySIP: func(context.Context, configread.SIP) error { verified++; return nil },
|
|
DrainControls: func(context.Context) error { return nil },
|
|
}
|
|
if phase == "startup" {
|
|
err = bootstrap.Run(context.Background())
|
|
} else {
|
|
if err := database.NoteSIPChange(execute.DispatcherID, 9); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
runtime := &Runtime{Bootstrap: bootstrap, Logger: slog.New(slog.NewTextHandler(io.Discard, nil))}
|
|
current := policySnapshot(t).SIP
|
|
err = runtime.refreshSIP(context.Background(), ¤t)
|
|
}
|
|
fenced := phase == "startup" && errors.Is(err, store.ErrSIPPending) || phase == "notification" && err == nil
|
|
if !fenced || applied != 0 || verified != 0 {
|
|
t.Fatalf("occupied SIP load was not fenced: error=%v applied=%d verified=%d", err, applied, verified)
|
|
}
|
|
occupied, err = database.OccupiedCalls(execute.DispatcherID)
|
|
if err != nil || occupied != 1 {
|
|
t.Fatalf("SIP update released occupied execution: %d %v", occupied, err)
|
|
}
|
|
if admitted, err := database.CanAdmit(execute.DispatcherID, 1001, "task-asr"); err != nil || admitted {
|
|
t.Fatalf("occupied SIP update reopened admission: %v %v", admitted, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|