Исключение Testcontainers при запуске

Кто-нибудь знает, почему я иногда получаю исключение, когда использую Selenium вместе с Testcontainers. См. ниже:

Произошло исключение: CLR/OpenQA.Selenium.WebDriverException Исключение типа «OpenQA.Selenium.WebDriverException» возникло в WebDriver.dll, но не было обработано в коде пользователя: «Обнаружено неизвестное исключение при отправке HTTP-запроса на удаленный сервер WebDriver для URL-адреса http://localhost:4444/session . Сообщение об исключении: «Произошла ошибка при отправке запроса». Найдены внутренние исключения, подробнее см. $exception в окне переменных. Самое внутреннее исключение System.IO.IOException : ответ завершился преждевременно. в System.Net.Http.HttpConnection.d__61.MoveNext()

Это происходит в половине случаев, когда я запускаю следующий конструктор тестов (C#/xUnit.net):

public DockerShould()
{
    var gridNetwork = new NetworkBuilder()
        .WithName("gridNetwork")
        .Build();

    const int SessionPort = 4444;
    var containerHub = new ContainerBuilder()
        .WithImage("selenium/hub:4.8")
        .WithName("selenium-hub")
        .WithPortBinding(4442, 4442)
        .WithPortBinding(4443, 4443)
        .WithPortBinding(SessionPort, SessionPort)
        .WithNetwork(gridNetwork)
        .Build();

    var firefoxEnvironment = new Dictionary<string, string>()
    {
        {"SE_EVENT_BUS_HOST", "selenium-hub"},
        {"SE_EVENT_BUS_PUBLISH_PORT", "4442"},
        {"SE_EVENT_BUS_SUBSCRIBE_PORT", "4443"}
    };

    var containerFirefox = new ContainerBuilder()
        .WithImage("selenium/node-firefox:4.8")
        .WithEnvironment(firefoxEnvironment)
        .WithNetwork(gridNetwork)
        .Build();

    var firefoxVideoEnvironment = new Dictionary<string, string>()
    {
        {"DISPLAY_CONTAINER_NAME", "firefox"},
        {"FILE_NAME", "firefox.mp4"}
    };      
    
    var containerFirefoxVideo = new ContainerBuilder()
        .WithImage("selenium/video:ffmpeg-4.3.1-20230210")
        .WithNetwork(gridNetwork)            
        .WithEnvironment(firefoxVideoEnvironment)
        // .WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(SessionPort))
        .Build();        
    
    gridNetwork.CreateAsync().Wait();
    containerHub.StartAsync().Wait();
    containerFirefox.StartAsync().Wait();
    containerFirefoxVideo.StartAsync().Wait();

    Thread.Sleep(5000);
    _remoteWebDriver = new RemoteWebDriver(new Uri("http://localhost:4444"), new FirefoxOptions());
}

Исключение возникает при создании нового RemoteWebDriver. Я добавил thread.sleep, чтобы дать небольшую задержку перед созданием переменной. Я не уверен, что это действительно помогает. Есть ли более элегантный способ убедиться, что все контейнеры запущены, прежде чем пытаться создать веб-драйвер (что, как я предполагаю, является проблемой)?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
74
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

В вашей конфигурации есть несколько недостатков. Я не уверен, какой из них в конечном итоге вызывает проблему, но ниже я привел рабочий пример. Ключевые части были прокомментированы. Обратите внимание, что в примере не используется стратегия ожидания для определения готовности контейнера или службы внутри него. Это аспект, который вам все еще нужно будет решить. Но сначала давайте взглянем на некоторые основы.

  1. Пожалуйста, прочитайте статью Использование асинхронного шаблона на основе задач. Контейнеры тестов для .NET используют асинхронный шаблон на основе задач (TAP). Я заметил, что вы склонны часто блокировать асинхронный контекст.
  2. Вам не нужно привязывать порты для связи между контейнерами.
  3. Избегайте использования фиксированных привязок портов, таких как WithPortBinding(4444, 4444). Чтобы предотвратить конфликты портов, назначьте случайный порт хоста с помощью WithPortBinding(4444, true) и извлеките его из экземпляра контейнера с помощью GetMappedPublicPort(4444).
  4. Не используйте фиксированные имена контейнеров по той же причине, что и в 3. Вместо этого используйте WithNetworkAliases(string).
  5. Не используйте localhost для доступа к службам, работающим внутри контейнеров. Конечная точка зависит от среды Docker. Вместо этого используйте свойство Hostname.
public sealed class StackOverflow : IAsyncLifetime
{
    private const ushort WebDriverPort = 4444;

    private readonly INetwork _network;

    private readonly IContainer _selenium;

    private readonly IContainer _firefox;

    private readonly IContainer _ffmpg;

    public StackOverflow()
    {
        _network = new NetworkBuilder()
            .Build();

        _selenium = new ContainerBuilder()
            .WithImage("selenium/hub:4.8")

            // Use random assigned host ports to access the service running inside the containers.
            .WithPortBinding(WebDriverPort, true)
            .WithNetwork(_network)

            // Use a network-alias to communication between containers.
            .WithNetworkAliases(nameof(_selenium))
            .Build();

        _firefox = new ContainerBuilder()
            .WithImage("selenium/node-firefox:4.8")
            .WithEnvironment("SE_EVENT_BUS_HOST", nameof(_selenium))
            .WithEnvironment("SE_EVENT_BUS_PUBLISH_PORT", "4442")
            .WithEnvironment("SE_EVENT_BUS_SUBSCRIBE_PORT", "4443")
            .WithNetwork(_network)
            .WithNetworkAliases(nameof(_firefox))
            .Build();

        _ffmpg = new ContainerBuilder()
            .WithImage("selenium/video:ffmpeg-4.3.1-20230210")
            .WithEnvironment("DISPLAY_CONTAINER_NAME", nameof(_firefox))
            .WithEnvironment("FILE_NAME", nameof(_firefox) + ".mp4")
            .WithNetwork(_network)
            .WithNetworkAliases(nameof(_ffmpg))
            .Build();
    }

    public async Task InitializeAsync()
    {
        await _network.CreateAsync()
            .ConfigureAwait(false);

        // You can await Task.WhenAll(params Task[]) too.
        await _selenium.StartAsync()
            .ConfigureAwait(false);

        await _firefox.StartAsync()
            .ConfigureAwait(false);

        await _ffmpg.StartAsync()
            .ConfigureAwait(false);
    }

    public async Task DisposeAsync()
    {
        await _selenium.DisposeAsync()
            .ConfigureAwait(false);

        await _firefox.DisposeAsync()
            .ConfigureAwait(false);

        await _ffmpg.DisposeAsync()
            .ConfigureAwait(false);

        await _network.DeleteAsync()
            .ConfigureAwait(false);
    }

    [Fact]
    public async Task Question()
    {
        // TODO: The container configurations mentioned above lack a wait strategy. It is crucial that you add a wait strategy to each of them to determine readiness (afterwards remove this line).
        await Task.Delay(TimeSpan.FromSeconds(15))
            .ConfigureAwait(false);

        // Use the Hostname property instead of localhost. Get the random assigned host port with GetMappedPublicPort(ushort).
        var webDriver = new RemoteWebDriver(new UriBuilder(Uri.UriSchemeHttp, _selenium.Hostname, _selenium.GetMappedPublicPort(WebDriverPort)).Uri, new FirefoxOptions());
        Assert.NotNull(webDriver.SessionId);
    }
}

Я хотел бы спросить вас, пожалуйста: что вы используете в режиме селена хаба и узла? Я рекомендовал использовать в этом случае автономный режим — и почему? Потому что тесткоанинер webDriver на мой взгляд работает как динамическая сетка в s:docker-selenium github Я также спрашиваю, потому что я просто работаю над этим: Feature-контейнер WebDriver Поэтому я хотел бы узнать ваше мнение и узнать, как я могу сопоставить возможности testcotanienr и RemoteWebDriver.

Другие вопросы по теме