using Exchanger.Core.Configuration;
using Godot;
using System;
using System.Linq;
using System.Threading.Tasks;
using PromotionPlayer = Exchanger.UI.AdvertisementPlayer.AdvertisementPlayer;
namespace Exchanger.Tests.Runtime;
///
/// Сквозная проверка штатного lifecycle промо-плеера с Native Video.
/// Реальное оборудование не используется; пути к роликам в журнал не выводятся.
///
public partial class NativeVideoLifecycleSmoke : Node
{
private const int Cycles = 50;
private const int RecreateEvery = 10;
private const int HideEvery = 5;
private PackedScene _playerScene = null!;
private PromotionPlayer? _host;
public override async void _Ready()
{
try
{
string[] paths = OS.GetCmdlineUserArgs()
.Where(argument => !argument.StartsWith("--", StringComparison.Ordinal))
.Take(2)
.ToArray();
if (paths.Length < 2)
{
Fail("требуются два внешних пути к видео");
return;
}
_playerScene = ResourceLoader.Load(
"res://src/ui/AdvertisementPlayer/AdvertisementPlayer.tscn");
await CreatePlayerAsync();
for (int cycle = 0; cycle < Cycles; cycle++)
{
PromotionPlayer host = _host!;
host.Configure(new AdvertisementSettings
{
Enabled = true,
Muted = false,
VideoPaths = [paths[cycle % paths.Length]],
FallbackText = "ПРОВЕРКА ПРОМО",
});
await WaitFramesAsync(6);
VideoStreamPlayer player = host.GetNode("VideoPlayer");
if (player.Stream is null || !player.IsPlaying())
{
Fail($"ролик не запустился в цикле {cycle}");
return;
}
if ((cycle + 1) % HideEvery == 0)
{
host.Visible = false;
await WaitFramesAsync(2);
if (player.Stream is not null || player.IsPlaying())
{
Fail($"скрытый промо-блок не освободил stream в цикле {cycle}");
return;
}
host.Visible = true;
await WaitFramesAsync(6);
if (player.Stream is null || !player.IsPlaying() || player.StreamPosition > 0.5)
{
Fail($"промо-блок не перезапустился с начала в цикле {cycle}");
return;
}
}
if ((cycle + 1) % RecreateEvery == 0 && cycle + 1 < Cycles)
{
host.QueueFree();
_host = null;
await WaitFramesAsync(3);
await CreatePlayerAsync();
}
}
_host!.QueueFree();
_host = null;
await WaitFramesAsync(4);
GD.Print($"ADVERTISEMENT_LIFECYCLE: PASS — {Cycles} source changes completed");
GetTree().Quit(0);
}
catch (Exception exception)
{
Fail($"необработанная ошибка lifecycle: {exception.GetType().Name}");
}
}
private async Task CreatePlayerAsync()
{
_host = _playerScene.Instantiate();
AddChild(_host);
await WaitFramesAsync(2);
}
private async Task WaitFramesAsync(int count)
{
for (int frame = 0; frame < count; frame++)
{
await ToSignal(GetTree(), SceneTree.SignalName.ProcessFrame);
}
}
private void Fail(string reason)
{
GD.PushError("ADVERTISEMENT_LIFECYCLE: FAIL — " + reason);
if (GodotObject.IsInstanceValid(_host))
{
_host!.QueueFree();
}
GetTree().Quit(1);
}
}