Есть отличная удаленная работа для php+codeception+jenkins+allure+docker спецов. 100% remote! Присоединиться к проекту

apache.http.client Не получается выполнить post запрос на удаленную машину


(Александр Беликов) #1

Всем привет.
Необходимо в тесте вызвать метод, который отправит файл .json в контроллер запущенного приложения, для создания определенной фикстуры (например user). Проблема в том, что локально под Windows это отрабатывает, а на удаленной виртуалке (linux) - нет.
Вот метод, который реализует отправку:

package utils;

import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class HttpTransport {

    public static void sendJsonToController(String json, String url) throws IOException {
        url = "http://127.0.0.1:9000/" + url;
        HttpClient client = HttpClientBuilder.create().build();
        HttpPost post = new HttpPost(url);
        List<NameValuePair> urlParameters = new ArrayList<NameValuePair>();
        urlParameters.add(new BasicNameValuePair("json", json));
        post.setEntity(new UrlEncodedFormEntity(urlParameters, "UTF-8"));
        client.execute(post);
    }
}

Валится, при попытке выполнить


    client.execute(post);

    org.apache.http.conn.HttpHostConnectException: Connect to 127.0.0.1:9000 [/127.0.0.1] failed: Connection refused
	at java.net.PlainSocketImpl.socketConnect(Native Method)
	at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339)
	at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200)
	at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182)
	at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
	at java.net.Socket.connect(Socket.java:579)
	at org.apache.http.conn.socket.PlainConnectionSocketFactory.connectSocket(PlainConnectionSocketFactory.java:72)
	at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:117)
	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:314)
	at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:363)
	at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:219)
	at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:195)
	at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:86)
	at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108)
	at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:186)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:106)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:57)
	at utils.HttpTransport.sendJsonToController(HttpTransport.java:23)

Но самое удивительное то, что следом запускаются тесты, которые не дергают это метод для создания фикстур, а идут прямиком на localhost:9000, и отрабатывают через UI. И эти тесты проходят. Т.е приложение запущено, факт, и отрабатывает на localhost:9000. Замена localhost:9000 на 127.0.0.1 не помогла. Приложение использует протокол tcp4. Как это можно победить?


(Sergey Korol) #2

Внимательно читаем FAQ. Почти месяц на сайте и до сих пор не научились форматировать код.

Касательно вашей проблемы:

Каким образом вы собираетесь подключаться к удаленке, указав localhost? Логично, что для отправки запроса к удаленному сервису, вам нужно указать IP удаленной VM.


(Александр Беликов) #3

Поясню. Имеется CI Hudson. При старте job-а происходит запуск приложения на всех виртуальных машинах. После того, как приложение на всем ВМ запустилось, выполняется подключение нодов на виртуалках к хабу, который запущен на том же серваке что и Hudson. Как только ноды зарегились, выполняется команда mvn test


(Александр Беликов) #4

У меня 8 виртуальных машин, я никогда не знаю заранее что и где будет выполняться, как хаб распределит тесты по нодам - одному богу известно. И как мне 8 IP-шников прописывать?


(Sergey Korol) #5

А плохо, что вы не можете управлять своим хабом. Ведь распределение во многом зависит от заданной конфигурации. При определенном подходе, вы всегда сможете перенаправлять команды в строго указанное место.

Но разговор не об этом. Ваш сервис развернут по определенному адресу в сети, и если тесты запускаются в месте, отличном от задеплоенного приложения, то о каких localhost / 127.0.0.1 вообще речь? И причем тут 8 IP, если сервис 1?

Или вы разворачиваете приложение на 8ми VM и нужно каждому отправить запрос? В таком случае естественно придется указывать строго тот IP, по которому надо отправить запрос. А как вы иначе хотели? Адреса нодов знаете? Знаете. Заводите доп. параметры в xml (если используется TestNG), парсите во время выполнения и передавайте соответствующие IP в URL запроса.

Ну и возвращаясь к проблеме распределения между нодами: кастомный CapabilityMatcher + некий уникальный идентификатор VM / browser / OS помогут посылать команды туда, куда вы захотите, а не первому свободному ноду.


(sidelnikovmike) #6

Ну если вы знаете все 8 адресов, а нужный только 1 - внесите в конфиг и пингуйте все по очереди.


(Александр Беликов) #7

Благодаря @ArtOfLife кое что прояснилось. Конечно же, ни о каком localhost и речи быть не может. Необходимо указывать IP адрес виртуалки. Что было проделано. Из 8-ми виртуальных машин была оставлена всего одна, остальные семь выключил. В коде, в методе, где происходит передача файла в контроллер приложения был явно задан IP единственной виртуальной машины. Тесты были запущены в 1 поток, и они прошли. Но тут же столкновение с новой трудностью. Виртуалок то 8 шт. Соответственно, нужно где то хранить IP-шники 8-ми виртуалок, доставать их, и использовать в методе. Все тот же @ArtOfLife посоветовал использовать в файле testng.xml Попробовал использовать эту схему, но пока что то не получается. Параметр успешно парсится с помощью @Parameter({nodeIP}), передается в метод отправки, но тесты не проходят, видимо все таки hub Selenium Grid-а отправляет тесты не туда куда нужно. Вопрос к сожалению остается открытым.


(vmaximv) #8

Все это гуглится на раз


(Александр Беликов) #9

Мне известны IP-шники нодов


(Sergey Korol) #10

@vmaximv намекнул, что вы можете решить свою задачу еще проще. После создания инстанса RemoteWebDriver, вы сможете получить доступ к текущей сессии, из которой в свою очередь можно получить node ip. Его то нам и нужно передать в качестве url для отправки запроса контроллеру.

Единственная оговорка: в случае, если вы запускаете тесты на одинаковых конфигурациях, вам придется ограничить максимальное число инстансов браузера на нод = 1. Иначе при ваших 8 параллельных потоках, по крайней мере 5 тестов полезут на первый свободный.


(Александр Беликов) #11

Спасибо, завтра попробую, отпишу что получилось