Nock выбрасывает несоответствие для запроса при использовании Promise.race - PullRequest
0 голосов
/ 05 февраля 2020

Я пишу тест для некоторого кода, который будет использовать Promise.race, чтобы вернуть результат из сервиса graphql, который работает (может быть) на нескольких серверах. Я использовал Nock для насмешки над запросом, который отлично работает, когда я запускаю один сервис. Когда я макетирую несколько сервисов, Нок выдает ошибку, говоря

AssertionError: ожидается, что [Function] не выдаст ошибку, но 'Ошибка: Ошибка: Nock: Нет соответствия для запроса {\ n "method" : "POST", \ n "url": "http://94.82.155.133: 35204 ", \ n "заголовки": {\ n "тип контента": "application / json", \ n "accept": "application / json" \ n}, \ n "body": "{...}" \ n} 'было брошено

мой тест выглядит так:

it('should make two POST requests to the service for data from graphQL', async () => {
  const spy = sinon.spy(releases, '_queryGraphQL');
  const releaseID = 403615894;
  nock.cleanAll();
  const services = serviceDetails(NUMBER_OF_SERVICES); // NUMBER_OF_SERVICES = 3
  nock(serviceDiscoveryHost)
    .get('/v1/catalog/service/state51')
    .reply(HTTP_CODES.OK, services);

  for (const service of services) {
    const currentNodeHealth = nodeHealth(service.Node);
    nock(serviceDiscoveryHost)
      .get('/v1/health/node/'+service.Node)
      .reply(HTTP_CODES.OK, currentNodeHealth);

    const delayTime = Math.floor(Math.random()*1000);
    nock('http://'+service.Address+':'+service.ServicePort, serviceHeaders)
      .post('/')
      .delay(delayTime)
      .replyWithError({code: 'ETIMEDOUT', connect: false})
      .post('/')
      .delay(delayTime)
      .reply(HTTP_CODES.OK, getReply(releaseID))
  }

  const actual = await releases.getRelease(releaseID)
    .catch((err) => {
      console.log(releases._retries);
      (() => { throw err; }).should.not.throw();
    });
  expect(releases._retries[releaseID]).to.be.equal(1);
  expect(spy.callCount).to.be.equal(2);
  expect(actual).to.be.an('object')
  expect(actual.data.ReleaseFormatById.id).to.be.equal(releaseID);
});

, и бит кода выглядит как

async _queryGraphQL(releaseID, services) {
    if (! this._retries[releaseID]) {
      this._retries[releaseID] = 0;
    }

    const postData = this._getReleaseQuery(releaseID);

    return Promise.race(services.map( (service) => {
      const options = this._getHTTPRequestOptions(service);

      return new Promise((resolve, reject) => {
        let post = this.http.request(options, (res) => {
          let data = '';
          if (res.statusCode < 200 || res.statusCode > 299) {
            const msg = this.SERVICE_NAME + ' returned a status code outside of acceptable range: ' + res.statusCode;
            reject(new QueryError(msg, postData));
          } else {
            res.setEncoding('utf8');
            res.on('data', (chunk) => {
              data += chunk;
            });

            res.on('error', (err) => {
              reject(new QueryError(err.message, postData, err));
            });

            res.on('end', () => {
              resolve(JSON.parse(data));
            });
          }
        });
        post.on('error', async (err) => {
          if (err.code === 'ETIMEDOUT') {
            if (this._retries[releaseID] &&
                this._retries[releaseID] === 3) {
              reject(err);
            } else {
              this._retries[releaseID] += 1;
              resolve(this._queryGraphQL(releaseID, services));
            }
          } else {
            reject(new QueryError(err.message, postData, err));
          }
        });

        post.write(JSON.stringify(postData));
        post.end();
      });
    }));
  }

this.http просто require('http');. и варианты будут {hostname: service.hostname} \\ example.com et c.

Я ожидаю, что если первая служба ответит с ошибкой, касающейся: «ETIMEDOUT», она вызовет (еще 2 раза) и попробуйте все службы снова, пока первая служба, которая ответит, не будет «ETIMEDOUT».

...