Implement platform management features
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user