101 lines
3.2 KiB
Go
101 lines
3.2 KiB
Go
package dispatcher
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"log/slog"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"sync/atomic"
|
|
"testing"
|
|
|
|
"git.ipao.vip/rogee/go-sip/internal/configread"
|
|
)
|
|
|
|
func TestSIPNotificationPersistsBarrierAndWaitsForLoadedFullSnapshot(t *testing.T) {
|
|
executor, _, _, s := newExecuteFixture(t)
|
|
approved := policySnapshot(t).SIP
|
|
changed := approved
|
|
changed.Revision = 9
|
|
newSIP, err := json.Marshal(changed)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
var body []byte
|
|
switch r.URL.Path {
|
|
case "/internal/v1/dispatcher/sip":
|
|
body = newSIP
|
|
default:
|
|
t.Errorf("unexpected HTTP path %s", r.URL.Path)
|
|
w.WriteHeader(http.StatusNotFound)
|
|
return
|
|
}
|
|
_, _ = w.Write(body)
|
|
}))
|
|
defer server.Close()
|
|
client, err := configread.NewClient(server.URL, executor.DispatcherID, "test-secret", server.Client())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var loaded atomic.Bool
|
|
var applied atomic.Int32
|
|
verify := func(_ context.Context, sip configread.SIP) error {
|
|
if applied.Load() == 0 {
|
|
return errors.New("SIP load checked before native apply")
|
|
}
|
|
if sip.Revision != 9 || !loaded.Load() {
|
|
return errors.New("Agent and Asterisk have not applied SIP revision 9")
|
|
}
|
|
return nil
|
|
}
|
|
runtime := &Runtime{Bootstrap: Bootstrap{DispatcherID: executor.DispatcherID, Client: client, Store: s,
|
|
ApplySIP: func(_ context.Context, sip configread.SIP) error {
|
|
if sip.Revision != 9 {
|
|
return errors.New("wrong SIP revision sent to Agent")
|
|
}
|
|
applied.Add(1)
|
|
if !loaded.Load() {
|
|
return errors.New("native Asterisk SIP reload is still unavailable")
|
|
}
|
|
return nil
|
|
}, VerifySIP: verify}, Logger: slog.Default()}
|
|
|
|
body := []byte(strings.Replace(string(configExample(t, "mq-sip-change")), `"revision":8`, `"revision":9`, 1))
|
|
if err := runtime.handleControl(context.Background(), "", body); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if admitted, err := s.CanAdmit(executor.DispatcherID, 1001, "task-asr"); err != nil || admitted {
|
|
t.Fatalf("SIP notification did not close admission: %v %v", admitted, err)
|
|
}
|
|
if applied, pending, err := s.SIPState(executor.DispatcherID); err != nil || applied != 8 || pending != 9 {
|
|
t.Fatalf("notification not durable before ACK: %d %d %v", applied, pending, err)
|
|
}
|
|
if err := runtime.refreshSIP(context.Background(), &approved); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if admitted, err := s.CanAdmit(executor.DispatcherID, 1001, "task-asr"); err != nil || admitted {
|
|
t.Fatalf("unloaded SIP reopened admission: %v %v", admitted, err)
|
|
}
|
|
if applied.Load() == 0 {
|
|
t.Fatal("notification never sent to Agent")
|
|
}
|
|
loaded.Store(true)
|
|
if err := runtime.refreshSIP(context.Background(), &approved); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if admitted, err := s.CanAdmit(executor.DispatcherID, 1001, "task-asr"); err != nil || !admitted {
|
|
t.Fatalf("verified SIP did not reopen: %v %v", admitted, err)
|
|
}
|
|
if approved.Revision != 9 {
|
|
t.Fatalf("reloaded SIP not bound: rev=%d", approved.Revision)
|
|
}
|
|
bound, err := s.ReadSnapshot(executor.DispatcherID, 1001, "task-asr")
|
|
if err != nil || bound.SIP.Revision != 9 {
|
|
t.Fatalf("existing task did not inherit the approved SIP revision: %+v %v", bound.SIP, err)
|
|
}
|
|
}
|