feat: align legacy operator and playout behavior
This commit is contained in:
@@ -325,7 +325,7 @@ public sealed class DynamicK3dSessionTests
|
||||
"GetScenePlayerOnChannel:9",
|
||||
"LoadScene:test-scene",
|
||||
"SetOutputChannelIndex:9",
|
||||
"SetSceneEffectType:1:7:12",
|
||||
"SetSceneEffectType:10:7:12",
|
||||
"BeginTransaction",
|
||||
"GetObject:headline",
|
||||
"SetValue:headline:safe value",
|
||||
@@ -360,12 +360,12 @@ public sealed class DynamicK3dSessionTests
|
||||
[
|
||||
new PlayoutUseBackground(true),
|
||||
new PlayoutSetBackgroundTexture("Video/background.vrv"),
|
||||
new PlayoutSetBackgroundVideo("Video/background.vrv", 2, true),
|
||||
new PlayoutSetBackgroundVideo("Video/background.vrv", 2, 10),
|
||||
new PlayoutSetValue("headline", "value"),
|
||||
new PlayoutSetBackgroundVideo(
|
||||
"Video/background.vrv",
|
||||
3,
|
||||
true,
|
||||
1,
|
||||
PlayoutMutationTiming.InTransaction),
|
||||
new PlayoutSetAssetValue("badge", "Images/badge.png"),
|
||||
new PlayoutSetVisible("badge", false),
|
||||
@@ -406,10 +406,10 @@ public sealed class DynamicK3dSessionTests
|
||||
{
|
||||
"LoadScene:test-scene",
|
||||
"SetOutputChannelIndex:9",
|
||||
"SetSceneEffectType:1:7:4",
|
||||
"SetSceneEffectType:10:7:4",
|
||||
"UseBackground:1",
|
||||
"SetBackgroundTexture:background.vrv",
|
||||
"SetBackgroundVideo:background.vrv:2:1",
|
||||
"SetBackgroundVideo:background.vrv:2:10",
|
||||
"BeginTransaction",
|
||||
"GetObject:headline",
|
||||
"SetValue:headline:value",
|
||||
@@ -469,16 +469,16 @@ public sealed class DynamicK3dSessionTests
|
||||
"test-scene.t2s",
|
||||
"test-scene",
|
||||
[new PlayoutField("headline", "page two", true)],
|
||||
FadeDuration: 59,
|
||||
FadeDuration: 19,
|
||||
Mutations:
|
||||
[
|
||||
new PlayoutUseBackground(false),
|
||||
new PlayoutSetBackgroundTexture("Video/background.vrv"),
|
||||
new PlayoutSetBackgroundVideo("Video/background.vrv", 4, true),
|
||||
new PlayoutSetBackgroundVideo("Video/background.vrv", 4, 10),
|
||||
new PlayoutSetBackgroundVideo(
|
||||
"Video/background.vrv",
|
||||
8,
|
||||
true,
|
||||
1,
|
||||
PlayoutMutationTiming.InTransaction),
|
||||
new PlayoutSetVisible("badge", false)
|
||||
]));
|
||||
@@ -516,7 +516,7 @@ public sealed class DynamicK3dSessionTests
|
||||
{
|
||||
"UseBackground:0",
|
||||
"SetBackgroundTexture:background.vrv",
|
||||
"SetBackgroundVideo:background.vrv:4:1",
|
||||
"SetBackgroundVideo:background.vrv:4:10",
|
||||
"BeginTransaction",
|
||||
"GetObject:headline",
|
||||
"SetValue:headline:page two",
|
||||
@@ -774,6 +774,7 @@ public sealed class DynamicK3dSessionTests
|
||||
|
||||
scene.QueryVariablesFailure = null;
|
||||
session.TakeOut(options.LayoutIndex, PlayoutTakeOutScope.All);
|
||||
Assert.True(session.HasPendingTakeOutCallbacks);
|
||||
callbacks.Fire("OnStopAll", 1);
|
||||
Assert.Equal(
|
||||
1,
|
||||
@@ -847,6 +848,7 @@ public sealed class DynamicK3dSessionTests
|
||||
1,
|
||||
session.ProcessPendingCallbacks(options.LayoutIndex).UnloadedSceneCount);
|
||||
Assert.False(session.HasPendingLifecycleCallbacks);
|
||||
Assert.False(session.HasPendingTakeOutCallbacks);
|
||||
session.Disconnect();
|
||||
return true;
|
||||
},
|
||||
@@ -1300,7 +1302,7 @@ public sealed class DynamicK3dSessionTests
|
||||
"KTAPConnect:1:127.0.0.1:30001:0",
|
||||
"GetScenePlayer",
|
||||
"LoadScene:test-scene",
|
||||
"SetSceneEffectType:1:7:12",
|
||||
"SetSceneEffectType:10:7:12",
|
||||
"BeginTransaction",
|
||||
"QueryVariables",
|
||||
"EndTransaction",
|
||||
|
||||
@@ -8,7 +8,9 @@ public sealed class LegacyParityStartupCompositionResolverTests
|
||||
[Fact]
|
||||
public void AbsentLocalConfiguration_UsesValidatedLegacyDefaultAtConfiguredFade()
|
||||
{
|
||||
using var scenes = TemporarySceneDirectory.Create("5001.t2s");
|
||||
using var scenes = TemporarySceneDirectory.Create(
|
||||
"5001.t2s",
|
||||
PlayoutSceneCompositionFactory.LegacyStartupDefaultBackgroundAssetPath);
|
||||
CreateBackground(scenes, PlayoutSceneCompositionFactory.LegacyDefaultBackgroundFileName);
|
||||
var options = new PlayoutOptions
|
||||
{
|
||||
@@ -23,9 +25,9 @@ public sealed class LegacyParityStartupCompositionResolverTests
|
||||
Assert.False(result.HasWarning);
|
||||
Assert.Equal(11, result.Composition.FadeDuration);
|
||||
Assert.Equal(LegacySceneBackgroundKind.Video, result.Composition.BackgroundKind);
|
||||
Assert.Equal("기본.vrv", result.Composition.BackgroundAssetPath);
|
||||
Assert.Equal(@"video\기본.vrv", result.Composition.BackgroundAssetPath);
|
||||
Assert.Equal(
|
||||
PlayoutAssetRoot.OperatorBackgroundDirectory,
|
||||
PlayoutAssetRoot.SceneDirectory,
|
||||
result.Composition.BackgroundAssetRoot);
|
||||
}
|
||||
|
||||
@@ -33,6 +35,7 @@ public sealed class LegacyParityStartupCompositionResolverTests
|
||||
public void AbsentLocalConfigurationAndMissingDefault_RemainsNoneWithBoundedWarning()
|
||||
{
|
||||
using var scenes = TemporarySceneDirectory.Create("5001.t2s");
|
||||
CreateBackground(scenes, PlayoutSceneCompositionFactory.LegacyDefaultBackgroundFileName);
|
||||
var options = new PlayoutOptions
|
||||
{
|
||||
SceneDirectory = scenes.Path,
|
||||
@@ -57,8 +60,9 @@ public sealed class LegacyParityStartupCompositionResolverTests
|
||||
[Fact]
|
||||
public void ExplicitLocalNone_IsHonoredEvenWhenLegacyDefaultExists()
|
||||
{
|
||||
using var scenes = TemporarySceneDirectory.Create("5001.t2s");
|
||||
CreateBackground(scenes, PlayoutSceneCompositionFactory.LegacyDefaultBackgroundFileName);
|
||||
using var scenes = TemporarySceneDirectory.Create(
|
||||
"5001.t2s",
|
||||
PlayoutSceneCompositionFactory.LegacyStartupDefaultBackgroundAssetPath);
|
||||
var options = new PlayoutOptions
|
||||
{
|
||||
SceneDirectory = scenes.Path,
|
||||
|
||||
@@ -61,6 +61,8 @@ internal sealed class FakeK3dSession : IK3dGuardedConnectSession
|
||||
|
||||
public bool HasPendingPlayCallbacks { get; set; }
|
||||
|
||||
public bool HasPendingTakeOutCallbacks { get; set; }
|
||||
|
||||
public bool ClearPendingLifecycleCallbacksAfterProcess { get; set; } = true;
|
||||
|
||||
public ConcurrentQueue<string> Calls { get; } = new();
|
||||
@@ -196,6 +198,7 @@ internal sealed class FakeK3dSession : IK3dGuardedConnectSession
|
||||
{
|
||||
HasPendingLifecycleCallbacks = false;
|
||||
HasPendingPlayCallbacks = false;
|
||||
HasPendingTakeOutCallbacks = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -384,7 +384,7 @@ public sealed class PlayoutSafetyValidationTests : IDisposable
|
||||
new PlayoutSetBackgroundVideo(
|
||||
"studio.vrv",
|
||||
LoopCount: 2004,
|
||||
LoopInfinite: true,
|
||||
LoopInfinite: 10,
|
||||
AssetRoot: PlayoutAssetRoot.OperatorBackgroundDirectory)
|
||||
]));
|
||||
|
||||
@@ -412,7 +412,7 @@ public sealed class PlayoutSafetyValidationTests : IDisposable
|
||||
new PlayoutSetBackgroundVideo(
|
||||
"Video\\background.vrv",
|
||||
LoopCount: 2004,
|
||||
LoopInfinite: true,
|
||||
LoopInfinite: 10,
|
||||
AssetRoot: PlayoutAssetRoot.OperatorBackgroundDirectory)
|
||||
])));
|
||||
}
|
||||
@@ -436,7 +436,7 @@ public sealed class PlayoutSafetyValidationTests : IDisposable
|
||||
new PlayoutSetBackgroundVideo(
|
||||
"studio.vrv",
|
||||
LoopCount: 2004,
|
||||
LoopInfinite: true,
|
||||
LoopInfinite: 10,
|
||||
AssetRoot: PlayoutAssetRoot.OperatorBackgroundDirectory)
|
||||
]));
|
||||
|
||||
@@ -460,7 +460,7 @@ public sealed class PlayoutSafetyValidationTests : IDisposable
|
||||
new PlayoutSetBackgroundVideo(
|
||||
"Video/background.vrv",
|
||||
LoopCount: 2004,
|
||||
LoopInfinite: true)
|
||||
LoopInfinite: 10)
|
||||
]));
|
||||
|
||||
var video = Assert.IsType<PlayoutSetBackgroundVideo>(Assert.Single(resolved.Mutations!));
|
||||
@@ -471,6 +471,27 @@ public sealed class PlayoutSafetyValidationTests : IDisposable
|
||||
ignoreCase: true);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(-1)]
|
||||
[InlineData(2)]
|
||||
[InlineData(9)]
|
||||
[InlineData(11)]
|
||||
public void ResolveCue_RejectsBackgroundVideoLoopModesNotUsedByMainForm(int loopMode)
|
||||
{
|
||||
var validated = ValidatedPlayoutOptions.Create(ValidTestOptions());
|
||||
|
||||
Assert.Throws<PlayoutRequestException>(() => validated.ResolveCue(new PlayoutCue(
|
||||
"test-scene.t2s",
|
||||
"test-scene",
|
||||
Mutations:
|
||||
[
|
||||
new PlayoutSetBackgroundVideo(
|
||||
"Video/background.vrv",
|
||||
LoopCount: 2004,
|
||||
LoopInfinite: loopMode)
|
||||
])));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("../outside.vrv")]
|
||||
[InlineData("Video/missing.vrv")]
|
||||
|
||||
@@ -15,6 +15,33 @@ public sealed class PlayoutSceneCompositionFactoryTests
|
||||
Assert.Null(result.BackgroundAssetPath);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0)]
|
||||
[InlineData(6)]
|
||||
[InlineData(19)]
|
||||
public void Fade_AcceptsOriginalDissolveComboIndexRange(int fadeDuration)
|
||||
{
|
||||
var result = PlayoutSceneCompositionFactory.Create(new PlayoutOptions
|
||||
{
|
||||
LegacySceneFadeDuration = fadeDuration
|
||||
});
|
||||
|
||||
Assert.Equal(fadeDuration, result.FadeDuration);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(-1)]
|
||||
[InlineData(20)]
|
||||
[InlineData(60)]
|
||||
public void Fade_RejectsValuesOutsideOriginalDissolveComboIndexRange(int fadeDuration)
|
||||
{
|
||||
Assert.Throws<PlayoutConfigurationException>(() =>
|
||||
PlayoutSceneCompositionFactory.Create(new PlayoutOptions
|
||||
{
|
||||
LegacySceneFadeDuration = fadeDuration
|
||||
}));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TrustedRelativeVideo_IsVerifiedEvenInDryRun()
|
||||
{
|
||||
@@ -92,4 +119,44 @@ public sealed class PlayoutSceneCompositionFactoryTests
|
||||
new PlayoutOptions { SceneDirectory = scenes.Path },
|
||||
fadeDuration: 6));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LegacyStartupDefault_UsesCutsVideo_NotSiblingBackgroundRoot()
|
||||
{
|
||||
using var scenes = TemporarySceneDirectory.Create(
|
||||
"5001.t2s",
|
||||
PlayoutSceneCompositionFactory.LegacyStartupDefaultBackgroundAssetPath);
|
||||
var backgroundRoot = Path.Combine(Directory.GetParent(scenes.Path)!.FullName, "배경");
|
||||
Directory.CreateDirectory(backgroundRoot);
|
||||
File.WriteAllText(
|
||||
Path.Combine(
|
||||
backgroundRoot,
|
||||
PlayoutSceneCompositionFactory.LegacyDefaultBackgroundFileName),
|
||||
"trusted F2/F3 background");
|
||||
|
||||
var result = PlayoutSceneCompositionFactory.CreateLegacyStartupDefault(
|
||||
new PlayoutOptions { SceneDirectory = scenes.Path },
|
||||
fadeDuration: 6);
|
||||
|
||||
Assert.Equal(@"video\기본.vrv", result.BackgroundAssetPath);
|
||||
Assert.Equal(PlayoutAssetRoot.SceneDirectory, result.BackgroundAssetRoot);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LegacyStartupDefault_MissingCutsVideo_FailsEvenWhenSiblingDefaultExists()
|
||||
{
|
||||
using var scenes = TemporarySceneDirectory.Create("5001.t2s");
|
||||
var backgroundRoot = Path.Combine(Directory.GetParent(scenes.Path)!.FullName, "배경");
|
||||
Directory.CreateDirectory(backgroundRoot);
|
||||
File.WriteAllText(
|
||||
Path.Combine(
|
||||
backgroundRoot,
|
||||
PlayoutSceneCompositionFactory.LegacyDefaultBackgroundFileName),
|
||||
"trusted F2/F3 background");
|
||||
|
||||
Assert.Throws<PlayoutConfigurationException>(() =>
|
||||
PlayoutSceneCompositionFactory.CreateLegacyStartupDefault(
|
||||
new PlayoutOptions { SceneDirectory = scenes.Path },
|
||||
fadeDuration: 6));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2448,6 +2448,71 @@ public sealed class TornadoPlayoutEngineTests
|
||||
Assert.True(engine.Status.IsPlayCompletionPending);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PendingTakeOutCallback_BlocksEveryFurtherSdkCommandUntilCompletion()
|
||||
{
|
||||
using var scenes = TemporarySceneDirectory.Create("5001.t2s", "5006.t2s");
|
||||
var completionReady = false;
|
||||
var session = new FakeK3dSession
|
||||
{
|
||||
SupportsLifecycleCallbacks = true,
|
||||
ClearPendingLifecycleCallbacksAfterProcess = false
|
||||
};
|
||||
session.TakeOutAction = (_, _) =>
|
||||
{
|
||||
session.HasPendingLifecycleCallbacks = true;
|
||||
session.HasPendingTakeOutCallbacks = true;
|
||||
};
|
||||
session.ProcessPendingCallbacksAction = _ =>
|
||||
{
|
||||
if (!completionReady)
|
||||
{
|
||||
return new K3dCallbackDrainResult(0, 0, false);
|
||||
}
|
||||
|
||||
session.HasPendingLifecycleCallbacks = false;
|
||||
session.HasPendingTakeOutCallbacks = false;
|
||||
return new K3dCallbackDrainResult(1, 1, false);
|
||||
};
|
||||
await using var engine = CreateEngine(
|
||||
TestOptions(scenes.Path, "5001", "5006"),
|
||||
new FakeK3dSessionFactory(() => session),
|
||||
new FakeRegistrationProbe(),
|
||||
new FakeTornadoProcessProbe(new TornadoProcessSnapshot(1, 1, 0)),
|
||||
liveAuthorized: false);
|
||||
|
||||
Assert.True((await engine.ConnectAsync(CancellationToken.None)).IsSuccess);
|
||||
Assert.True((await engine.PrepareAsync(
|
||||
Cue("5001"),
|
||||
CancellationToken.None)).IsSuccess);
|
||||
Assert.True((await engine.TakeOutAsync(
|
||||
PlayoutTakeOutScope.All,
|
||||
CancellationToken.None)).IsSuccess);
|
||||
Assert.True(engine.Status.IsTakeOutCompletionPending);
|
||||
Assert.False(engine.Status.IsCommandAvailable);
|
||||
|
||||
var prepare = await engine.PrepareAsync(Cue("5006"), CancellationToken.None);
|
||||
var repeatedTakeOut = await engine.TakeOutAsync(
|
||||
PlayoutTakeOutScope.All,
|
||||
CancellationToken.None);
|
||||
|
||||
Assert.Equal(PlayoutResultCode.Unavailable, prepare.Code);
|
||||
Assert.Equal(PlayoutResultCode.Unavailable, repeatedTakeOut.Code);
|
||||
Assert.Contains("CutOut/StopAll", prepare.Message, StringComparison.Ordinal);
|
||||
Assert.Equal(1, session.Calls.Count(call => call == "TakeOut:All"));
|
||||
Assert.DoesNotContain("Prepare:5006", session.Calls);
|
||||
|
||||
completionReady = true;
|
||||
await engine.PollProcessOnceAsync(CancellationToken.None);
|
||||
|
||||
Assert.False(engine.Status.IsTakeOutCompletionPending);
|
||||
Assert.True(engine.Status.IsCommandAvailable);
|
||||
Assert.True((await engine.PrepareAsync(
|
||||
Cue("5006"),
|
||||
CancellationToken.None)).IsSuccess);
|
||||
Assert.Equal(1, session.Calls.Count(call => call == "Prepare:5006"));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(PlayoutTakeOutScope.All)]
|
||||
[InlineData(PlayoutTakeOutScope.Layout)]
|
||||
|
||||
Reference in New Issue
Block a user