Implement platform management features

This commit is contained in:
npc0-hue
2026-08-17 08:48:45 +08:00
parent 65353cf269
commit 302f1f64b7
38 changed files with 2185 additions and 110 deletions
+83 -1
View File
@@ -3,6 +3,7 @@ package service
import (
"path/filepath"
"strings"
"sync"
"testing"
"time"
@@ -74,7 +75,7 @@ func TestCoreServicePublishesLogEventsForAcceptedBatch(t *testing.T) {
}
select {
case event := <-subscription.Events:
if event.Stream.ID != "log-1" || event.Entry.Seq != 1 || event.LatestSeq != 1 {
if event.Kind != LogEventSubscriptionEventLog || event.LogEvent.Stream.ID != "log-1" || event.LogEvent.Entry.Seq != 1 || event.LogEvent.LatestSeq != 1 {
t.Fatalf("unexpected log event: %+v", event)
}
case <-time.After(time.Second):
@@ -91,6 +92,76 @@ func TestCoreServicePublishesLogEventsForAcceptedBatch(t *testing.T) {
}
}
func TestCoreServicePersistsAndEnforcesImmutableProcessLogSessionMetadata(t *testing.T) {
svc, sessionToken := newRegisteredLogIngestService(t)
startedAt := time.Date(2026, 7, 3, 12, 30, 0, 0, time.UTC)
streamID := runSessionLogStreamID("run-local", "server-1", "session-a", "stdout")
batch := validLogBatch(t, sessionToken, 1, 1)
batch.LogStreamID = streamID
batch.LogSessionID = "session-a"
batch.SessionStartedAt = startedAt
if _, err := svc.IngestLogBatch(batch); err != nil {
t.Fatalf("ingest session-scoped process batch: %v", err)
}
stream, err := svc.GetLogStream(streamID)
if err != nil || stream.LogSessionID != "session-a" || !stream.SessionStartedAt.Equal(startedAt) {
t.Fatalf("session metadata was not persisted: stream=%+v err=%v", stream, err)
}
conflict := validLogBatch(t, sessionToken, 2, 2)
conflict.LogStreamID = streamID
conflict.LogSessionID = "session-a"
conflict.SessionStartedAt = startedAt.Add(time.Second)
if _, err := svc.IngestLogBatch(conflict); err == nil || !strings.Contains(err.Error(), "metadata must match") {
t.Fatalf("expected immutable stream metadata rejection, got %v", err)
}
legacy := createLogStreamFixture(t, svc)
legacyBatch := validLogBatch(t, sessionToken, 1, 1)
legacyBatch.LogStreamID = legacy.ID
legacyBatch.LogSessionID = "session-a"
legacyBatch.SessionStartedAt = startedAt
if _, err := svc.IngestLogBatch(legacyBatch); err == nil || !strings.Contains(err.Error(), "metadata must match") {
t.Fatalf("expected legacy stream to reject attached session metadata, got %v", err)
}
}
func TestCoreServiceSerializesConsistentSessionStreamCreation(t *testing.T) {
svc, _ := newRegisteredLogIngestService(t)
startedAt := time.Date(2026, 7, 3, 12, 30, 0, 0, time.UTC)
streams := []domain.LogStream{
{ID: "session-stream-stdout", ServerInstanceID: "server-1", Source: domain.LogStreamSourceProcess, StreamKey: "stdout", LogSessionID: "session-a", SessionStartedAt: startedAt, StorageBackend: domain.LogStorageBackendLocalSegments, RetentionPolicy: "default"},
{ID: "session-stream-stderr", ServerInstanceID: "server-1", Source: domain.LogStreamSourceProcess, StreamKey: "stderr", LogSessionID: "session-a", SessionStartedAt: startedAt, StorageBackend: domain.LogStorageBackendLocalSegments, RetentionPolicy: "default"},
}
errorsByStream := make(chan error, len(streams))
var wait sync.WaitGroup
for _, stream := range streams {
stream := stream
wait.Add(1)
go func() {
defer wait.Done()
_, err := svc.CreateLogStream(stream)
errorsByStream <- err
}()
}
wait.Wait()
close(errorsByStream)
for err := range errorsByStream {
if err != nil {
t.Fatalf("create consistent session stream: %v", err)
}
}
_, err := svc.CreateLogStream(domain.LogStream{ID: "session-stream-conflict", ServerInstanceID: "server-1", Source: domain.LogStreamSourceProcess, StreamKey: "console", LogSessionID: "session-a", SessionStartedAt: startedAt.Add(time.Second), StorageBackend: domain.LogStorageBackendLocalSegments, RetentionPolicy: "default"})
if err == nil || !strings.Contains(err.Error(), "conflicts") {
t.Fatalf("expected conflicting session timestamp rejection, got %v", err)
}
_, err = svc.CreateLogStream(domain.LogStream{ID: "session-file-tail", ServerInstanceID: "server-1", Source: domain.LogStreamSourceFile, StreamKey: "file", LogSessionID: "session-file", SessionStartedAt: startedAt, StorageBackend: domain.LogStorageBackendLocalSegments, RetentionPolicy: "default"})
if err == nil || !strings.Contains(err.Error(), "only valid for process") {
t.Fatalf("expected file-tail session metadata rejection, got %v", err)
}
}
func TestCoreServiceLogBatchDuplicateAck(t *testing.T) {
svc, sessionToken := newRegisteredLogIngestService(t)
createLogStreamFixture(t, svc)
@@ -346,6 +417,17 @@ func TestCoreServiceAcceptsLegacyAutonomousJobLogStreamWithoutPlatformJob(t *tes
}
}
func TestCoreServiceRejectsSessionMetadataOnLegacyAutonomousStreamID(t *testing.T) {
svc, sessionToken := newRegisteredLogIngestService(t)
batch := validLogBatch(t, sessionToken, 1, 1)
batch.LogStreamID = jobLogStreamID("autonomous-bootstrap-start", "stdout")
batch.LogSessionID = "session-a"
batch.SessionStartedAt = time.Date(2026, 7, 3, 12, 30, 0, 0, time.UTC)
if _, err := svc.IngestLogBatch(batch); err == nil {
t.Fatal("expected session-scoped batch with legacy autonomous stream ID to be rejected")
}
}
func TestCoreServiceRejectsOutOfOrderAndConflictingLogBatches(t *testing.T) {
svc, sessionToken := newRegisteredLogIngestService(t)
createLogStreamFixture(t, svc)