docker compose jest интеграционные тесты не могут выполнять внутриконтейнерные http-запросы RequestError: Ошибка: getaddrinfo ENOTFOUND - PullRequest
0 голосов
/ 11 мая 2018

У меня есть стек для создания докеров с несколькими контейнерами.Этими двумя являются расширенный контейнер python:3-onbuild (см. Базовое изображение здесь ) с запущенным веб-сервером falcon и базовый контейнер node:8.11-alpine, который пытается отправлять запросы на веб-сервер python.Веб-сервер python выполняет вызовы из базы данных в контейнер postgres:alpine.Это упрощенная версия моего docker-compose.yml файла:

version: '3.6'

services:
  app: # python:3-onbuild
    ports:
      - 5000
    build:
      context: ../../
      dockerfile: infra/docker/app.Dockerfile

  lambda: # node:8.11-alpine
    ports:
      - 10000
    build:
      context: ../../
      dockerfile: infra/docker/lambda.Dockerfile
    depends_on:
      - app

   db: # postgres:alpine
      ports:
        - 5432:5432
      build:
        context: ../../
        dockerfile: infra/docker/db.Dockerfile

У меня есть набор интеграционных тестов, которые я пытаюсь пройти.Когда я запускаю тесты с конечной точкой во внешнем мире (сервер Python https, работающий с тем же кодом, что и служба app), все тесты проходят.Проблема возникает, когда я пытаюсь сделать эти запросы к службе app из моего стека docker-compose, в частности от службы lambda к службе app.

Я так не думаюэто проблема времени.В функции beforeAll моего набора jest я опрашиваю сервер python в течение 100 секунд, один раз каждые 10 секунд, например:

В моем тесте jest

beforeAll(async () => {
    const endpointUrl = getEndpointUrl();
    const status = await checkStatus(endpointUrl, 10);

    // NOTE: never reaches this line, starts tests before 5-minute timeout
    console.log(`[integration.test]: status = ${status}`);
}, 5 * 60 * 1000); // 5-minute timeout for async function

Где checkStatus()определяется

/**
 * Checks the status of the backend every 10 seconds, n times
 * @param {string} endpointUrl 
 * @param {number} n 
 */
export function checkStatus(endpointUrl: string, n: number): Promise<string> {
    console.log(`[lib][checkStatus]: before timeout date = ${Date()}`);
    return new Promise<string>((resolve, reject) => {
        checkStatusHelper(endpointUrl, n, resolve, reject);
    });
}

function checkStatusHelper(endpointUrl, n, resolve, reject): void {
    if (n === 0) reject();
    setTimeout(() => {
        console.log(`[lib][checkStatus]: after timeout date ${n} = ${Date()}`);
        rp.get(`${endpointUrl}/status`)
            .then(res => {
                console.log(`[lib][checkStatus]: after request date = ${Date()}`);
                console.log(`[lib][checkStatus]: res = ${res}`);
                resolve('success');
            })
            .catch(err => {
                console.log(`[lib][checkStatus]: err = ${err}`);
                checkStatusHelper(endpointUrl, n - 1, resolve, reject);
            });
    }, 10 * 1000);
}

Я получаю вывод, подобный следующему (с request-promise-native):

  console.log src/lib.ts:30
    [lib][checkStatus]: before timeout date = Fri May 11 2018 01:54:10 GMT+0000 (UTC)

  console.log src/lib.ts:39
    [lib][checkStatus]: after timeout date 10 = Fri May 11 2018 01:54:20 GMT+0000 (UTC)

  console.log src/lib.ts:47
    [lib][checkStatus]: err = RequestError: Error: getaddrinfo ENOTFOUND app app:5000

  console.log src/lib.ts:39
    [lib][checkStatus]: after timeout date 9 = Fri May 11 2018 01:54:31 GMT+0000 (UTC)

  console.log src/lib.ts:47
    [lib][checkStatus]: err = RequestError: Error: getaddrinfo ENOTFOUND app app:5000

# etc ...

И аналогичный вывод с axios вместо request-promise-native

  console.log src/lib.ts:30
    [lib][checkStatus]: before timeout date = Fri May 11 2018 01:56:57 GMT+0000 (UTC)

  console.log src/lib.ts:39
    [lib][checkStatus]: after timeout date 10 = Fri May 11 2018 01:57:07 GMT+0000 (UTC)

  console.error node_modules/jsdom/lib/jsdom/virtual-console.js:29
    Error: Error: getaddrinfo ENOTFOUND app app:5000
        at Object.dispatchError (/Halloo/node_modules/jsdom/lib/jsdom/living/xhr-utils.js:65:19)
        at Request.client.on.err (/Halloo/node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:676:20)
        at emitOne (events.js:121:20)
        at Request.emit (events.js:211:7)
        at Request.onRequestError (/Halloo/node_modules/request/request.js:878:8)
        at emitOne (events.js:116:13)
        at ClientRequest.emit (events.js:211:7)
        at Socket.socketErrorListener (_http_client.js:387:9)
        at emitOne (events.js:116:13)
        at Socket.emit (events.js:211:7) undefined

  console.log src/lib.ts:47
    [lib][checkStatus]: err = Error: Network Error

  console.log src/lib.ts:39
    [lib][checkStatus]: after timeout date 9 = Fri May 11 2018 01:57:18 GMT+0000 (UTC)

  console.error node_modules/jsdom/lib/jsdom/virtual-console.js:29
    Error: Error: getaddrinfo ENOTFOUND app app:5000
        at Object.dispatchError (/Halloo/node_modules/jsdom/lib/jsdom/living/xhr-utils.js:65:19)
        at Request.client.on.err (/Halloo/node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:676:20)
        at emitOne (events.js:121:20)
        at Request.emit (events.js:211:7)
        at Request.onRequestError (/Halloo/node_modules/request/request.js:878:8)
        at emitOne (events.js:116:13)
        at ClientRequest.emit (events.js:211:7)
        at Socket.socketErrorListener (_http_client.js:387:9)
        at emitOne (events.js:116:13)
        at Socket.emit (events.js:211:7) undefined

  console.log src/lib.ts:47
    [lib][checkStatus]: err = Error: Network Error

# etc ...

Я также не думаю, что это не проблема сети.Если я закомментирую свой тестовый шаг и позволю сервису lambda нормально развернуться, я могу зайти в lambda-контейнер и проверить соединение, используя axios или request-promise-native.Эта конечная точка /status просто возвращает все имена таблиц в моей базе данных, чтобы убедиться, что контейнер базы данных также работает правильно.Это работает почти мгновенно, и гораздо раньше, чем за 100 секунд

$ node
> const axios = require('axios')
undefined
> axios.get('http://app:5000/status').then(res => console.log(res.data));
Promise {
  <pending>,
  domain:
   Domain {
     domain: null,
     _events: { error: [Function: debugDomainError] },
     _eventsCount: 1,
     _maxListeners: undefined,
     members: [] } }
> [ [ 'table0' ],
    [ 'table1' ],
    [ 'table2' ],
    [ 'table3' ],
    [ 'table4' ],
    [ 'table5' ] ]

Я подумал, что, может быть, я не смогу использовать шутку для этих целей, но я чувствую, что могу, потому что все работает без нареканий, когда я изменяю URL своей продукции.Конечная точка https работает в aws и закомментируйте шаг beforeAll() в моем наборе шуток.

1 Ответ

0 голосов
/ 11 мая 2018

Это закончилось проблемой с моей конфигурацией шуток

Средой по умолчанию в Jest является среда, подобная браузеру, через jsdom. Если вы создаете службу узла, вы можете использовать опцию узла для использования среды, подобной узлу.

Чтобы это исправить, мне нужно было добавить это в мой файл jest.config.js:

{
  // ...
  testEnvironment: 'node'
  // ...
}

Источник: https://github.com/axios/axios/issues/1418

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...