Я пишу тест для некоторого кода, который будет использовать 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».