Add remote session loading
This commit is contained in:
@@ -113,6 +113,23 @@ func (prepareStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*S
|
||||
registerConfigInput := func(kind, path, checksum, source string) {
|
||||
inputs = append(inputs, manifest.InputRecord{Kind: kind, Path: path, Checksum: checksum, Source: source})
|
||||
}
|
||||
registerSessionConfigInput := func(path, checksum string) {
|
||||
source := env.Config.SessionSource
|
||||
if strings.TrimSpace(source.Source) == "" {
|
||||
source.Source = "session_config"
|
||||
}
|
||||
inputs = append(inputs, manifest.InputRecord{
|
||||
Kind: "session_config",
|
||||
Path: path,
|
||||
Checksum: checksum,
|
||||
Source: source.Source,
|
||||
S3Bucket: source.S3Bucket,
|
||||
S3Key: source.S3Key,
|
||||
S3Size: source.S3Size,
|
||||
S3ETag: source.S3ETag,
|
||||
SpoolPath: source.SpoolPath,
|
||||
})
|
||||
}
|
||||
|
||||
campaignDst := filepath.Join(paths.InputsDir, "campaign.yml")
|
||||
campaignChecksum, err := copyFileIfChanged(env.ArtifactStore, campaignSrc, campaignDst)
|
||||
@@ -126,7 +143,7 @@ func (prepareStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*S
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("prepare: materialize session.yml: %w", err)
|
||||
}
|
||||
registerConfigInput("session_config", sessionDst, sessionChecksum, "session_config")
|
||||
registerSessionConfigInput(sessionDst, sessionChecksum)
|
||||
|
||||
pipelineResolvedBytes, err := renderResolvedPipeline(env.Config.Pipeline)
|
||||
if err != nil {
|
||||
|
||||
@@ -152,6 +152,64 @@ func TestPrepareStageIdempotent(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepareStageRecordsLocalSessionProvenance(t *testing.T) {
|
||||
env, m := setupPrepareEnv(t)
|
||||
root := filepath.Dir(env.Config.SessionPath)
|
||||
writeFile(t, filepath.Join(root, "audio", "a.flac"), "a")
|
||||
env.Config.Session.Inputs.AudioFiles = []string{"./audio/a.flac"}
|
||||
|
||||
if _, err := (prepareStage{}).Run(context.Background(), env, m); err != nil {
|
||||
t.Fatalf("prepare.Run() error = %v", err)
|
||||
}
|
||||
sessionInput := findManifestInput(t, m.Inputs, "session_config")
|
||||
if sessionInput.Source != "session_config" {
|
||||
t.Fatalf("session source = %q, want session_config", sessionInput.Source)
|
||||
}
|
||||
if sessionInput.S3Bucket != "" || sessionInput.S3Key != "" || sessionInput.SpoolPath != "" {
|
||||
t.Fatalf("local session input has unexpected remote provenance: %#v", sessionInput)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepareStageRecordsRemoteSessionProvenance(t *testing.T) {
|
||||
env, m := setupPrepareEnv(t)
|
||||
remoteSessionPath := filepath.Join(t.TempDir(), "downloaded-session.yml")
|
||||
writeFile(t, remoteSessionPath, "session_id: 2026-05-03\ninputs:\n audio_s3:\n prefix: audio/\n")
|
||||
env.Config.SessionPath = remoteSessionPath
|
||||
env.Config.Session.Inputs.AudioDir = ""
|
||||
env.Config.Session.Inputs.AudioS3 = &config.SessionAudioS3Input{Prefix: "audio/"}
|
||||
env.Config.SessionSource = config.SessionSource{
|
||||
Source: "session_config.s3",
|
||||
LocalPath: remoteSessionPath,
|
||||
S3Bucket: "my-dnd-archive",
|
||||
S3Key: "dnd/campaigns/sample-campaign/sessions/2026-05-03/session.yml",
|
||||
S3Size: 58,
|
||||
S3ETag: "session-etag",
|
||||
SpoolPath: remoteSessionPath,
|
||||
}
|
||||
env.Config.Pipeline.Spool = config.SpoolConfig{Root: filepath.Join(t.TempDir(), "spool")}
|
||||
env.Config.Pipeline.Storage.S3 = &config.StorageS3Config{Bucket: "my-dnd-archive", RootPrefix: "dnd"}
|
||||
m.RunID = "20260515T031522Z-a1b2c3d4"
|
||||
m.LocalWorkDir = artifacts.SessionRunRootForCampaign(env.Config.Pipeline.Workspace.Root, "sample-campaign", m.SessionID, m.RunID)
|
||||
m.LocalSpoolDir = artifacts.SessionSpoolAudioDir(env.Config.Pipeline.Spool.Root, "sample-campaign", m.SessionID, m.RunID)
|
||||
fake := &storage.FakeBackend{}
|
||||
fake.SeedObject(storage.FakeObject{Key: "dnd/campaigns/sample-campaign/sessions/2026-05-03/audio/alice.flac", Data: []byte("alice")})
|
||||
env.ObjectStore = fake
|
||||
|
||||
if _, err := (prepareStage{}).Run(context.Background(), env, m); err != nil {
|
||||
t.Fatalf("prepare.Run() error = %v", err)
|
||||
}
|
||||
sessionInput := findManifestInput(t, m.Inputs, "session_config")
|
||||
if sessionInput.Source != "session_config.s3" {
|
||||
t.Fatalf("session source = %q, want session_config.s3", sessionInput.Source)
|
||||
}
|
||||
if sessionInput.S3Bucket != "my-dnd-archive" || sessionInput.S3Key != "dnd/campaigns/sample-campaign/sessions/2026-05-03/session.yml" {
|
||||
t.Fatalf("remote session input missing bucket/key: %#v", sessionInput)
|
||||
}
|
||||
if sessionInput.S3Size != 58 || sessionInput.S3ETag != "session-etag" || sessionInput.SpoolPath != remoteSessionPath {
|
||||
t.Fatalf("remote session input missing metadata: %#v", sessionInput)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepareStageS3AudioDownloadAndMaterialization(t *testing.T) {
|
||||
env, m := setupPrepareEnv(t)
|
||||
env.Config.Session.Campaign = "forsaken"
|
||||
@@ -543,3 +601,14 @@ func snapshotInputs(inputs []manifest.InputRecord) map[string]string {
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func findManifestInput(t *testing.T, inputs []manifest.InputRecord, kind string) manifest.InputRecord {
|
||||
t.Helper()
|
||||
for _, input := range inputs {
|
||||
if input.Kind == kind {
|
||||
return input
|
||||
}
|
||||
}
|
||||
t.Fatalf("manifest input kind %q not found in %#v", kind, inputs)
|
||||
return manifest.InputRecord{}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user