Fail when creating a draft results in HTTP 200

Bug: Issue 7763
Change-Id: Ib16a486efdd4e5bbf4c2f1c8f8d5cd180980e1c5
This commit is contained in:
Wyatt Allen
2017-11-14 12:55:42 -08:00
parent d27d3c04ff
commit a0bce874f6
2 changed files with 113 additions and 14 deletions

View File

@@ -40,6 +40,11 @@
SEND_DIFF_DRAFT: 'sendDiffDraft',
};
const CREATE_DRAFT_UNEXPECTED_STATUS_MESSAGE =
'Saving draft resulted in HTTP 200 (OK) but expected HTTP 201 (Created)';
const HEADER_REPORTING_BLACKLIST = /^set-cookie$/i;
Polymer({
is: 'gr-rest-api-interface',
@@ -1636,6 +1641,7 @@
},
_sendDiffDraftRequest(method, changeNum, patchNum, draft) {
const isCreate = !draft.id && method === 'PUT';
let endpoint = '/drafts';
if (draft.id) {
endpoint += '/' + draft.id;
@@ -1652,6 +1658,11 @@
const promise = this.getChangeURLAndSend(changeNum, method, patchNum,
endpoint, body);
this._pendingRequests[Requests.SEND_DIFF_DRAFT].push(promise);
if (isCreate) {
return this._failForCreate200(promise);
}
return promise;
},
@@ -1996,5 +2007,34 @@
`/files/${encodedPath}/blame`, patchNum, undefined, undefined,
opt_base ? {base: 't'} : undefined);
},
/**
* Modify the given create draft request promise so that it fails and throws
* an error if the response bears HTTP status 200 instead of HTTP 201.
* @see Issue 7763
* @param {Promise} promise The original promise.
* @return {Promise} The modified promise.
*/
_failForCreate200(promise) {
return promise.then(result => {
if (result.status === 200) {
// Read the response headers into an object representation.
const headers = Array.from(result.headers.entries())
.reduce((obj, [key, val]) => {
if (!HEADER_REPORTING_BLACKLIST.test(key)) {
obj[key] = val;
}
return obj;
}, {});
const err = new Error([
CREATE_DRAFT_UNEXPECTED_STATUS_MESSAGE,
JSON.stringify(headers),
].join('\n'));
// Throw the error so that it is caught by gr-reporting.
throw err;
}
return result;
});
},
});
})();

View File

@@ -651,24 +651,83 @@ limitations under the License.
});
});
test('_sendDiffDraft pending requests tracked', () => {
const obj = element._pendingRequests;
sandbox.stub(element, 'getChangeURLAndSend', () => mockPromise());
assert.notOk(element.hasPendingDiffDrafts());
suite('draft comments', () => {
test('_sendDiffDraftRequest pending requests tracked', () => {
const obj = element._pendingRequests;
sandbox.stub(element, 'getChangeURLAndSend', () => mockPromise());
assert.notOk(element.hasPendingDiffDrafts());
element._sendDiffDraftRequest(null, null, null, {});
assert.equal(obj.sendDiffDraft.length, 1);
assert.isTrue(!!element.hasPendingDiffDrafts());
element._sendDiffDraftRequest(null, null, null, {});
assert.equal(obj.sendDiffDraft.length, 1);
assert.isTrue(!!element.hasPendingDiffDrafts());
element._sendDiffDraftRequest(null, null, null, {});
assert.equal(obj.sendDiffDraft.length, 2);
assert.isTrue(!!element.hasPendingDiffDrafts());
element._sendDiffDraftRequest(null, null, null, {});
assert.equal(obj.sendDiffDraft.length, 2);
assert.isTrue(!!element.hasPendingDiffDrafts());
for (const promise of obj.sendDiffDraft) { promise.resolve(); }
for (const promise of obj.sendDiffDraft) { promise.resolve(); }
return element.awaitPendingDiffDrafts().then(() => {
assert.equal(obj.sendDiffDraft.length, 0);
assert.isFalse(!!element.hasPendingDiffDrafts());
return element.awaitPendingDiffDrafts().then(() => {
assert.equal(obj.sendDiffDraft.length, 0);
assert.isFalse(!!element.hasPendingDiffDrafts());
});
});
suite('_failForCreate200', () => {
test('_sendDiffDraftRequest checks for 200 on create', () => {
const sendPromise = Promise.resolve();
sandbox.stub(element, 'getChangeURLAndSend').returns(sendPromise);
const failStub = sandbox.stub(element, '_failForCreate200')
.returns(Promise.resolve());
return element._sendDiffDraftRequest('PUT', 123, 4, {}).then(() => {
assert.isTrue(failStub.calledOnce);
assert.isTrue(failStub.calledWithExactly(sendPromise));
});
});
test('_sendDiffDraftRequest no checks for 200 on non create', () => {
sandbox.stub(element, 'getChangeURLAndSend')
.returns(Promise.resolve());
const failStub = sandbox.stub(element, '_failForCreate200')
.returns(Promise.resolve());
return element._sendDiffDraftRequest('PUT', 123, 4, {id: '123'})
.then(() => {
assert.isFalse(failStub.called);
});
});
test('_failForCreate200 fails on 200', done => {
const result = {
ok: true,
status: 200,
headers: {entries: () => [
['Set-CoOkiE', 'secret'],
['Innocuous', 'hello'],
]},
};
element._failForCreate200(Promise.resolve(result)).then(() => {
assert.isTrue(false, 'Promise should not resolve');
}).catch(e => {
assert.isOk(e);
assert.include(e.message, 'Saving draft resulted in HTTP 200');
assert.include(e.message, 'hello');
assert.notInclude(e.message, 'secret');
done();
});
});
test('_failForCreate200 does not fail on 201', done => {
const result = {
ok: true,
status: 201,
headers: {entries: () => []},
};
element._failForCreate200(Promise.resolve(result)).then(() => {
done();
}).catch(e => {
assert.isTrue(false, 'Promise should not fail');
});
});
});
});