|
|
|
|
package mock
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"strings"
|
|
|
|
|
"testing"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"tera-clone/services/tera-api/internal/directstream"
|
|
|
|
|
"tera-clone/services/tera-api/internal/domain"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func TestSharedDirectWriterReleaseTargetsOnlyItsOwnSession(t *testing.T) {
|
|
|
|
|
store := NewStore(time.Now)
|
|
|
|
|
authority := NewDirectTicketAuthority(store)
|
|
|
|
|
var claims []directstream.TicketClaims
|
|
|
|
|
for _, actor := range []string{"first", "second"} {
|
|
|
|
|
ctx := domain.WithActor(context.Background(), domain.Actor{Name: actor})
|
|
|
|
|
session, err := store.OpenDirectSession(ctx, "CH20", domain.DirectSessionRequest{Access: directstream.AccessWriter})
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
claim, err := authority.ConsumeTicket(ctx, session.StreamTicket, directstream.TicketBinding{Channel: "CH20", SessionID: session.SessionID})
|
|
|
|
|
if err != nil || claim.MaxAttachments != 4 {
|
|
|
|
|
t.Fatalf("claim: %+v, %v", claim, err)
|
|
|
|
|
}
|
|
|
|
|
claims = append(claims, claim)
|
|
|
|
|
}
|
|
|
|
|
if err := authority.ReleaseConsumedWriter(context.Background(), claims[0]); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
if store.directSessions[claims[0].SessionID].Access != directstream.AccessViewer || store.directSessions[claims[1].SessionID].Access != directstream.AccessWriter {
|
|
|
|
|
t.Fatal("release affected another writer")
|
|
|
|
|
}
|
|
|
|
|
if err := authority.CloseConsumedStream(context.Background(), claims[1]); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
if state := store.direct["CH20"]; state.Writer != "" || state.ViewerCount != 1 {
|
|
|
|
|
t.Fatalf("state: %+v", state)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDirectTicketAuthorityConsumesAuditsAndAppliesVerifiedLifecycle(t *testing.T) {
|
|
|
|
|
store := NewStore(time.Now)
|
|
|
|
|
ctx := domain.WithActor(context.Background(), domain.Actor{Name: "admin"})
|
|
|
|
|
session, err := store.OpenDirectSession(ctx, "CH01", domain.DirectSessionRequest{Access: directstream.AccessWriter})
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("open direct session: %v", err)
|
|
|
|
|
}
|
|
|
|
|
authority := NewDirectTicketAuthority(store)
|
|
|
|
|
claims, err := authority.ConsumeTicket(context.Background(), session.StreamTicket, directstream.TicketBinding{
|
|
|
|
|
SessionID: session.SessionID, Channel: session.Channel,
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("consume ticket: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if claims.Actor != "admin" || claims.Access != directstream.AccessWriter {
|
|
|
|
|
t.Fatalf("claims = %#v", claims)
|
|
|
|
|
}
|
|
|
|
|
store.mu.Lock()
|
|
|
|
|
store.runningRetention.LocalOperationEnabled = false
|
|
|
|
|
store.mu.Unlock()
|
|
|
|
|
connected := directstream.SessionEvent{
|
|
|
|
|
Type: directstream.SessionEventConnected, Source: "192.168.0.10",
|
|
|
|
|
Timestamp: time.Date(2026, 8, 13, 3, 4, 5, 0, time.UTC),
|
|
|
|
|
}
|
|
|
|
|
if err := authority.RecordConsumedStreamEvent(context.Background(), claims, connected); err != nil {
|
|
|
|
|
t.Fatalf("record connected stream event: %v", err)
|
|
|
|
|
}
|
|
|
|
|
disconnected := directstream.SessionEvent{
|
|
|
|
|
Type: directstream.SessionEventDisconnected, Source: connected.Source,
|
|
|
|
|
Timestamp: connected.Timestamp.Add(time.Minute),
|
|
|
|
|
}
|
|
|
|
|
if err := authority.RecordConsumedStreamEvent(context.Background(), claims, disconnected); err != nil {
|
|
|
|
|
t.Fatalf("record disconnected stream event: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if err := authority.ReleaseConsumedWriter(context.Background(), claims); err != nil {
|
|
|
|
|
t.Fatalf("release writer: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if err := authority.CloseConsumedStream(context.Background(), claims); err != nil {
|
|
|
|
|
t.Fatalf("close stream: %v", err)
|
|
|
|
|
}
|
|
|
|
|
events, err := store.AuditEvents(context.Background())
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
correlated := map[string]bool{
|
|
|
|
|
"direct.session.open": false,
|
|
|
|
|
"direct.stream.ticket.consume": false,
|
|
|
|
|
"direct.writer.release": false,
|
|
|
|
|
"direct.session.close": false,
|
|
|
|
|
}
|
|
|
|
|
for _, event := range events {
|
|
|
|
|
if _, required := correlated[event.Action]; required && event.Actor == "admin" && event.Result == "succeeded" && strings.Contains(event.Message, session.SessionID) {
|
|
|
|
|
correlated[event.Action] = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for action, found := range correlated {
|
|
|
|
|
if !found {
|
|
|
|
|
t.Fatalf("%s audit is not correlated by session %s: %#v", action, session.SessionID, events)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
portEvents, err := store.PortLogEvents(context.Background(), domain.PortLogFilter{Channel: "CH01", EventType: "session"})
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
wantWelcomeLog := strings.Join(strings.Fields(directstream.SessionEventMessage(claims, connected)), " ")
|
|
|
|
|
if len(portEvents) != 2 || portEvents[0].Actor != "admin/"+session.SessionID || portEvents[0].Message != wantWelcomeLog {
|
|
|
|
|
t.Fatalf("port session events = %#v", portEvents)
|
|
|
|
|
}
|
|
|
|
|
if !strings.Contains(portEvents[1].Message, "session disconnected") || !strings.Contains(portEvents[1].Message, "Serial channel: CH01") {
|
|
|
|
|
t.Fatalf("disconnect port event = %#v", portEvents[1])
|
|
|
|
|
}
|
|
|
|
|
}
|