Use project lookup

Specifying the project as part of the change ID when the /changes
endpoint is used can help reduce latency significantly.

This change modifies _changeBaseUrl to return a URL that specifies both
the project and the change number. As a portion of this, there may be an
API call made to get the project number (this is unlikely, but
possible). Due to that fact, _changeBaseUrl now returns a promise.

Bug: Issue 6708
Change-Id: I630e521cf6226e579e99aa3dc08cc17239d4dbd4
This commit is contained in:
Kasper Nilsson
2017-08-04 14:27:19 -07:00
parent 6c7c8af820
commit 6826659485
4 changed files with 266 additions and 213 deletions

View File

@@ -817,8 +817,8 @@
_setLabelValuesOnRevert(newChangeId) {
const labels = this.$.jsAPI.getLabelValuesPostRevert(this.change);
if (labels) {
const url = `/changes/${newChangeId}/revisions/current/review`;
this.$.restAPI.send(this.actions.revert.method, url, {labels});
this.$.restAPI.getChangeURLAndSend(newChangeId,
this.actions.revert.method, 'current', '/review', {labels});
}
},
@@ -878,11 +878,10 @@
cleanupFn();
return Promise.resolve();
}
const url = this.$.restAPI.getChangeActionURL(this.changeNum,
revisionAction ? this.patchNum : null, actionEndpoint);
return this.$.restAPI.send(method, url, payload,
this._handleResponseError, this).then(response => {
const patchNum = revisionAction ? this.patchNum : null;
return this.$.restAPI.getChangeURLAndSend(this.changeNum, method,
patchNum, actionEndpoint, payload, this._handleResponseError,
this).then(response => {
cleanupFn.call(this);
return response;
});

View File

@@ -71,12 +71,12 @@ limitations under the License.
send(method, url, payload) {
if (method !== 'POST') { return Promise.reject('bad method'); }
if (url === '/changes/42/revisions/2/submit') {
if (url === '/changes/test~42/revisions/2/submit') {
return Promise.resolve({
ok: true,
text() { return Promise.resolve(')]}\'\n{}'); },
});
} else if (url === '/changes/42/revisions/2/rebase') {
} else if (url === '/changes/test~42/revisions/2/rebase') {
return Promise.resolve({
ok: true,
text() { return Promise.resolve(')]}\'\n{}'); },
@@ -228,6 +228,8 @@ limitations under the License.
});
test('submit change', done => {
sandbox.stub(element.$.restAPI, '_getFromProjectLookup')
.returns(Promise.resolve('test'));
sandbox.stub(element, 'fetchIsLatestKnown',
() => { return Promise.resolve(true); });
element.change = {

View File

@@ -596,7 +596,8 @@
},
getChangeActionURL(changeNum, opt_patchNum, endpoint) {
return this._changeBaseURL(changeNum, opt_patchNum) + endpoint;
return this._changeBaseURL(changeNum, opt_patchNum)
.then(url => url + endpoint);
},
getChangeDetail(changeNum, opt_errFn, opt_cancelCondition) {
@@ -624,34 +625,34 @@
_getChangeDetail(changeNum, params, opt_errFn,
opt_cancelCondition) {
const url = this.getChangeActionURL(changeNum, null, '/detail');
const urlWithParams = this._urlWithParams(url, params);
return this._fetchRawJSON(
url,
opt_errFn,
opt_cancelCondition,
{O: params},
this._etags.getOptions(urlWithParams))
.then(response => {
if (response && response.status === 304) {
return Promise.resolve(
this._etags.getCachedPayload(urlWithParams));
} else {
const payloadPromise = response ?
this.getResponseObject(response) :
Promise.resolve();
payloadPromise.then(payload => {
this._etags.collect(urlWithParams, response, payload);
this._maybeInsertInLookup(payload);
});
return payloadPromise;
}
});
return this.getChangeActionURL(changeNum, null, '/detail').then(url => {
const urlWithParams = this._urlWithParams(url, params);
return this._fetchRawJSON(
url,
opt_errFn,
opt_cancelCondition,
{O: params},
this._etags.getOptions(urlWithParams))
.then(response => {
if (response && response.status === 304) {
return Promise.resolve(
this._etags.getCachedPayload(urlWithParams));
} else {
const payloadPromise = response ?
this.getResponseObject(response) :
Promise.resolve();
payloadPromise.then(payload => {
this._etags.collect(urlWithParams, response, payload);
this._maybeInsertInLookup(payload);
});
return payloadPromise;
}
});
});
},
getChangeCommitInfo(changeNum, patchNum) {
return this.fetchJSON(
this.getChangeActionURL(changeNum, patchNum, '/commit?links'));
return this._getChangeURLAndFetch(changeNum, '/commit?links', patchNum);
},
getChangeFiles(changeNum, patchRange) {
@@ -659,8 +660,8 @@
if (patchRange.basePatchNum !== 'PARENT') {
endpoint += '?base=' + encodeURIComponent(patchRange.basePatchNum);
}
return this.fetchJSON(
this.getChangeActionURL(changeNum, patchRange.patchNum, endpoint));
return this._getChangeURLAndFetch(changeNum, endpoint,
patchRange.patchNum);
},
getChangeFilesAsSpeciallySortedArray(changeNum, patchRange) {
@@ -689,9 +690,8 @@
},
getChangeRevisionActions(changeNum, patchNum) {
return this.fetchJSON(
this.getChangeActionURL(changeNum, patchNum, '/actions')).then(
revisionActions => {
return this._getChangeURLAndFetch(changeNum, '/actions', patchNum)
.then(revisionActions => {
// The rebase button on change screen is always enabled.
if (revisionActions.rebase) {
revisionActions.rebase.rebaseOnCurrent =
@@ -702,13 +702,11 @@
});
},
getChangeSuggestedReviewers(changeNum, inputVal, opt_errFn,
opt_ctx) {
const url =
this.getChangeActionURL(changeNum, null, '/suggest_reviewers');
const req = {n: 10};
if (inputVal) { req.q = inputVal; }
return this.fetchJSON(url, opt_errFn, opt_ctx, req);
getChangeSuggestedReviewers(changeNum, inputVal, opt_errFn) {
const params = {n: 10};
if (inputVal) { params.q = inputVal; }
return this._getChangeURLAndFetch(changeNum, '/suggest_reviewers', null,
opt_errFn, null, params);
},
_computeFilter(filter) {
@@ -808,30 +806,30 @@
},
_sendChangeReviewerRequest(method, changeNum, reviewerID) {
let url = this.getChangeActionURL(changeNum, null, '/reviewers');
let body;
switch (method) {
case 'POST':
body = {reviewer: reviewerID};
break;
case 'DELETE':
url += '/' + encodeURIComponent(reviewerID);
break;
default:
throw Error('Unsupported HTTP method: ' + method);
}
return this.getChangeActionURL(changeNum, null, '/reviewers')
.then(url => {
let body;
switch (method) {
case 'POST':
body = {reviewer: reviewerID};
break;
case 'DELETE':
url += '/' + encodeURIComponent(reviewerID);
break;
default:
throw Error('Unsupported HTTP method: ' + method);
}
return this.send(method, url, body);
return this.send(method, url, body);
});
},
getRelatedChanges(changeNum, patchNum) {
return this.fetchJSON(
this.getChangeActionURL(changeNum, patchNum, '/related'));
return this._getChangeURLAndFetch(changeNum, '/related', patchNum);
},
getChangesSubmittedTogether(changeNum) {
return this.fetchJSON(
this.getChangeActionURL(changeNum, null, '/submitted_together'));
return this._getChangeURLAndFetch(changeNum, '/submitted_together', null);
},
getChangeConflicts(changeNum) {
@@ -879,100 +877,84 @@
},
getReviewedFiles(changeNum, patchNum) {
return this.fetchJSON(
this.getChangeActionURL(changeNum, patchNum, '/files?reviewed'));
return this._getChangeURLAndFetch(changeNum, '/files?reviewed', patchNum);
},
saveFileReviewed(changeNum, patchNum, path, reviewed, opt_errFn, opt_ctx) {
const method = reviewed ? 'PUT' : 'DELETE';
const url = this.getChangeActionURL(changeNum, patchNum,
'/files/' + encodeURIComponent(path) + '/reviewed');
return this.send(method, url, null, opt_errFn, opt_ctx);
const e = `/files/${encodeURIComponent(path)}/reviewed`;
return this.getChangeURLAndSend(changeNum, method, patchNum, e, null,
opt_errFn, opt_ctx);
},
saveChangeReview(changeNum, patchNum, review, opt_errFn, opt_ctx) {
const url = this.getChangeActionURL(changeNum, patchNum, '/review');
return this.awaitPendingDiffDrafts()
.then(() => this.send('POST', url, review, opt_errFn, opt_ctx));
const promises = [
this.awaitPendingDiffDrafts(),
this.getChangeActionURL(changeNum, patchNum, '/review'),
];
return Promise.all(promises).then(([, url]) => {
return this.send('POST', url, review, opt_errFn, opt_ctx);
});
},
getChangeEdit(changeNum, opt_download_commands) {
const params = opt_download_commands ? {'download-commands': true} : null;
return this.getLoggedIn().then(loggedIn => {
return loggedIn ?
this.fetchJSON(
this.getChangeActionURL(changeNum, null, '/edit/'), null, null,
opt_download_commands ? {'download-commands': true} : null) :
false;
this._getChangeURLAndFetch(changeNum, '/edit/', null, null, null,
params) :
false;
});
},
getFileInChangeEdit(changeNum, path) {
return this.send('GET',
this.getChangeActionURL(changeNum, null,
'/edit/' + encodeURIComponent(path)
));
const e = '/edit/' + encodeURIComponent(path);
return this.getChangeURLAndSend(changeNum, 'GET', null, e);
},
rebaseChangeEdit(changeNum) {
return this.send('POST',
this.getChangeActionURL(changeNum, null,
'/edit:rebase'
));
return this.getChangeURLAndSend(changeNum, 'POST', null, '/edit:rebase');
},
deleteChangeEdit(changeNum) {
return this.send('DELETE',
this.getChangeActionURL(changeNum, null,
'/edit'
));
return this.getChangeURLAndSend(changeNum, 'DELETE', null, '/edit');
},
restoreFileInChangeEdit(changeNum, restore_path) {
return this.send('POST',
this.getChangeActionURL(changeNum, null, '/edit'),
{restore_path}
);
const p = {restore_path};
return this.getChangeURLAndSend(changeNum, 'POST', null, '/edit', p);
},
renameFileInChangeEdit(changeNum, old_path, new_path) {
return this.send('POST',
this.getChangeActionURL(changeNum, null, '/edit'),
{old_path},
{new_path}
);
const p = {old_path, new_path};
return this.getChangeURLAndSend(changeNum, 'POST', null, '/edit', p);
},
deleteFileInChangeEdit(changeNum, path) {
return this.send('DELETE',
this.getChangeActionURL(changeNum, null,
'/edit/' + encodeURIComponent(path)
));
const e = '/edit/' + encodeURIComponent(path);
return this.getChangeURLAndSend(changeNum, 'DELETE', null, e);
},
saveChangeEdit(changeNum, path, contents) {
return this.send('PUT',
this.getChangeActionURL(changeNum, null,
'/edit/' + encodeURIComponent(path)
),
contents
);
const e = '/edit/' + encodeURIComponent(path);
return this.getChangeURLAndSend(changeNum, 'PUT', null, e, contents);
},
// Deprecated, prefer to use putChangeCommitMessage instead.
saveChangeCommitMessageEdit(changeNum, message) {
const url = this.getChangeActionURL(changeNum, null, '/edit:message');
return this.send('PUT', url, {message});
const p = {message};
return this.getChangeURLAndSend(changeNum, 'PUT', null, '/edit:message',
p);
},
publishChangeEdit(changeNum) {
return this.send('POST',
this.getChangeActionURL(changeNum, null, '/edit:publish'));
return this.getChangeURLAndSend(changeNum, 'POST', null,
'/edit:publish');
},
putChangeCommitMessage(changeNum, message) {
const url = this.getChangeActionURL(changeNum, null, '/message');
return this.send('PUT', url, {message});
const p = {message};
return this.getChangeURLAndSend(changeNum, 'PUT', null, '/message', p);
},
saveChangeStarred(changeNum, starred) {
@@ -1014,7 +996,6 @@
getDiff(changeNum, basePatchNum, patchNum, path,
opt_errFn, opt_cancelCondition) {
const url = this._getDiffFetchURL(changeNum, patchNum, path);
const params = {
context: 'ALL',
intraline: null,
@@ -1023,13 +1004,10 @@
if (basePatchNum != PARENT_PATCH_NUM) {
params.base = basePatchNum;
}
const endpoint = `/files/${encodeURIComponent(path)}/diff`;
return this.fetchJSON(url, opt_errFn, opt_cancelCondition, params);
},
_getDiffFetchURL(changeNum, patchNum, path) {
return this._changeBaseURL(changeNum, patchNum) + '/files/' +
encodeURIComponent(path) + '/diff';
return this._getChangeURLAndFetch(changeNum, endpoint, patchNum,
opt_errFn, opt_cancelCondition, params);
},
getDiffComments(changeNum, opt_basePatchNum, opt_patchNum, opt_path) {
@@ -1086,11 +1064,20 @@
_getDiffComments(changeNum, endpoint, opt_basePatchNum,
opt_patchNum, opt_path) {
if (!opt_basePatchNum && !opt_patchNum && !opt_path) {
return this.fetchJSON(
this._getDiffCommentsFetchURL(changeNum, endpoint));
}
/**
* Fetches the comments for a given patchNum.
* Helper function to make promises more legible.
*
* @param {string|number} patchNum
* @return {!Object} Diff comments response.
*/
const fetchComments = patchNum => {
return this._getChangeURLAndFetch(changeNum, endpoint, patchNum);
};
if (!opt_basePatchNum && !opt_patchNum && !opt_path) {
return fetchComments();
}
function onlyParent(c) { return c.side == PARENT_PATCH_NUM; }
function withoutParent(c) { return c.side != PARENT_PATCH_NUM; }
function setPath(c) { c.path = opt_path; }
@@ -1098,16 +1085,13 @@
const promises = [];
let comments;
let baseComments;
const url =
this._getDiffCommentsFetchURL(changeNum, endpoint, opt_patchNum);
promises.push(this.fetchJSON(url).then(response => {
let fetchPromise;
fetchPromise = fetchComments(opt_patchNum).then(response => {
comments = response[opt_path] || [];
// TODO(kaspern): Implement this on in the backend so this can be
// removed.
// Sort comments by date so that parent ranges can be propagated in a
// single pass.
// TODO(kaspern): Implement this on in the backend so this can
// be removed.
// Sort comments by date so that parent ranges can be propagated
// in a single pass.
comments = this._setRanges(comments);
if (opt_basePatchNum == PARENT_PATCH_NUM) {
@@ -1117,18 +1101,17 @@
comments = comments.filter(withoutParent);
comments.forEach(setPath);
}));
});
promises.push(fetchPromise);
if (opt_basePatchNum != PARENT_PATCH_NUM) {
const baseURL = this._getDiffCommentsFetchURL(changeNum, endpoint,
opt_basePatchNum);
promises.push(this.fetchJSON(baseURL).then(response => {
baseComments = (response[opt_path] || []).filter(withoutParent);
fetchPromise = fetchComments(opt_basePatchNum).then(response => {
baseComments = (response[opt_path] || [])
.filter(withoutParent);
baseComments = this._setRanges(baseComments);
baseComments.forEach(setPath);
}));
});
promises.push(fetchPromise);
}
return Promise.all(promises).then(() => {
@@ -1140,7 +1123,8 @@
},
_getDiffCommentsFetchURL(changeNum, endpoint, opt_patchNum) {
return this._changeBaseURL(changeNum, opt_patchNum) + endpoint;
return this._changeBaseURL(changeNum, opt_patchNum)
.then(url => url + endpoint);
},
saveDiffDraft(changeNum, patchNum, draft) {
@@ -1171,9 +1155,9 @@
},
_sendDiffDraftRequest(method, changeNum, patchNum, draft) {
let url = this.getChangeActionURL(changeNum, patchNum, '/drafts');
let endpoint = '/drafts';
if (draft.id) {
url += '/' + draft.id;
endpoint += '/' + draft.id;
}
let body;
if (method === 'PUT') {
@@ -1184,7 +1168,8 @@
this._pendingRequests[Requests.SEND_DIFF_DRAFT] = [];
}
const promise = this.send(method, url, body);
const promise = this.getChangeURLAndSend(changeNum, method, patchNum,
endpoint, body);
this._pendingRequests[Requests.SEND_DIFF_DRAFT].push(promise);
return promise;
},
@@ -1210,11 +1195,10 @@
getChangeFileContents(changeId, patchNum, path, opt_parentIndex) {
const parent = typeof opt_parentIndex === 'number' ?
'?parent=' + opt_parentIndex : '';
return this._fetchB64File(
'/changes/' + encodeURIComponent(changeId) +
'/revisions/' + encodeURIComponent(patchNum) +
'/files/' + encodeURIComponent(path) +
'/content' + parent);
return this._changeBaseUrl(changeId, patchNum).then(url => {
url = `${url}/files/${encodeURIComponent(path)}/content${parent}`;
return this._fetchB64File(url);
});
},
getImagesForDiff(changeNum, diff, patchRange) {
@@ -1259,22 +1243,36 @@
});
},
_changeBaseURL(changeNum, opt_patchNum) {
let v = '/changes/' + changeNum;
if (opt_patchNum) {
v += '/revisions/' + opt_patchNum;
}
return v;
/**
* @param {string} changeNum
* @param {number|string=} opt_patchNum
* @param {string=} opt_project
* @return {!Promise<string>}
*/
_changeBaseURL(changeNum, opt_patchNum, opt_project) {
// TODO(kaspern): For full slicer migration, app should warn with a call
// stack every time _changeBaseURL is called without a project.
const projectPromise = opt_project ?
Promise.resolve(opt_project) :
this._getFromProjectLookup(changeNum);
return projectPromise.then(project => {
let url = `/changes/${encodeURIComponent(project)}~${changeNum}`;
if (opt_patchNum) {
url += `/revisions/${opt_patchNum}`;
}
return url;
});
},
setChangeTopic(changeNum, topic) {
return this.send('PUT', '/changes/' + encodeURIComponent(changeNum) +
'/topic', {topic}).then(this.getResponseObject);
const p = {topic};
return this.getChangeURLAndSend(changeNum, 'PUT', null, '/topic', p)
.then(this.getResponseObject);
},
setChangeHashtag(changeNum, hashtag) {
return this.send('POST', '/changes/' + encodeURIComponent(changeNum) +
'/hashtags', hashtag).then(this.getResponseObject);
return this.getChangeURLAndSend(changeNum, 'POST', null, '/hashtags',
hashtag).then(this.getResponseObject);
},
deleteAccountHttpPassword() {
@@ -1309,15 +1307,15 @@
return this.send('DELETE', '/accounts/self/sshkeys/' + id);
},
deleteVote(changeID, account, label) {
return this.send('DELETE', '/changes/' + changeID +
'/reviewers/' + account + '/votes/' + encodeURIComponent(label));
deleteVote(changeNum, account, label) {
const e = `/reviewers/${account}/votes/${encodeURIComponent(label)}`;
return this.getChangeURLAndSend(changeNum, 'DELETE', null, e);
},
setDescription(changeNum, patchNum, desc) {
return this.send('PUT',
this.getChangeActionURL(changeNum, patchNum, '/description'),
{description: desc});
const p = {description: desc};
return this.getChangeURLAndSend(changeNum, 'PUT', patchNum,
'/description', p);
},
confirmEmail(token) {
@@ -1331,14 +1329,12 @@
},
setAssignee(changeNum, assignee) {
return this.send('PUT',
this.getChangeActionURL(changeNum, null, '/assignee'),
{assignee});
const p = {assignee};
return this.getChangeURLAndSend(changeNum, 'PUT', null, '/assignee', p);
},
deleteAssignee(changeNum) {
return this.send('DELETE',
this.getChangeActionURL(changeNum, null, '/assignee'));
return this.getChangeURLAndSend(changeNum, 'DELETE', null, '/assignee');
},
probePath(path) {
@@ -1353,8 +1349,7 @@
if (opt_message) {
payload.message = opt_message;
}
const url = this.getChangeActionURL(changeNum, null, '/wip');
return this.send('POST', url, payload)
return this.getChangeURLAndSend(changeNum, 'POST', null, '/wip', payload)
.then(response => {
if (response.status === 204) {
return 'Change marked as Work In Progress.';
@@ -1363,16 +1358,15 @@
},
startReview(changeNum, opt_body, opt_errFn) {
return this.send(
'POST', this.getChangeActionURL(changeNum, null, '/ready'),
return this.getChangeURLAndSend(changeNum, 'POST', null, '/ready',
opt_body, opt_errFn);
},
deleteComment(changeNum, patchNum, commentID, reason) {
const url = this.changeBaseURL(changeNum, patchNum) +
'/comments/' + commentID + '/delete';
return this.send('POST', url, {reason}).then(response =>
this.getResponseObject(response));
const endpoint = `/comments/${commentID}/delete`;
const payload = {reason};
return this.getChangeURLAndSend(changeNum, 'POST', patchNum, endpoint,
payload).then(this.getResponseObject);
},
/**
@@ -1382,6 +1376,7 @@
* @return {Promise<Object>} The change
*/
getChange(changeNum) {
// Cannot use _changeBaseURL, as this function is used by _projectLookup.
return this.fetchJSON(`/changes/${changeNum}`);
},
@@ -1415,5 +1410,44 @@
return change.project;
});
},
/**
* Alias for _changeBaseURL.then(send).
*
* @param {string|number} changeNum
* @param {string} method
* @param {string} endpoint
* @param {string|number=} opt_patchNum
* @param {!Object=} opt_payload
* @param {function(?Response, string)=} opt_errFn
* @return {!Promise<!Object>}
*/
getChangeURLAndSend(changeNum, method, opt_patchNum, endpoint, opt_payload,
opt_errFn, opt_ctx, opt_contentType) {
return this._changeBaseURL(changeNum, opt_patchNum).then(url => {
return this.send(method, url + endpoint, opt_payload, opt_errFn,
opt_ctx, opt_contentType);
});
},
/**
* Alias for _changeBaseURL.then(fetchJSON).
*
* @param {string|number} changeNum
* @param {string} endpoint
* @param {string|number=} opt_patchNum
* @param {function(?Response, string)=} opt_errFn
* @param {!function()=} opt_cancelCondition
* @param {!Object=} opt_params
* @param {!Object=} opt_options
* @return {!Promise<!Object>}
*/
_getChangeURLAndFetch(changeNum, endpoint, opt_patchNum, opt_errFn,
opt_cancelCondition, opt_params, opt_options) {
return this._changeBaseURL(changeNum, opt_patchNum).then(url => {
return this.fetchJSON(url + endpoint, opt_errFn, opt_cancelCondition,
opt_params, opt_options);
});
},
});
})();

View File

@@ -269,8 +269,10 @@ limitations under the License.
});
test('differing patch diff comments are properly grouped', done => {
sandbox.stub(element, '_getFromProjectLookup')
.returns(Promise.resolve('test'));
sandbox.stub(element, 'fetchJSON', url => {
if (url == '/changes/42/revisions/1') {
if (url === '/changes/test~42/revisions/1') {
return Promise.resolve({
'/COMMIT_MSG': [],
'sieve.go': [
@@ -285,7 +287,7 @@ limitations under the License.
},
],
});
} else if (url == '/changes/42/revisions/2') {
} else if (url === '/changes/test~42/revisions/2') {
return Promise.resolve({
'/COMMIT_MSG': [],
'sieve.go': [
@@ -606,8 +608,7 @@ limitations under the License.
test('_sendDiffDraft pending requests tracked', () => {
const obj = element._pendingRequests;
sandbox.stub(element, 'send', () => mockPromise());
sandbox.stub(element, 'getChangeActionURL');
sandbox.stub(element, 'getChangeURLAndSend', () => mockPromise());
assert.notOk(element.hasPendingDiffDrafts());
element._sendDiffDraftRequest(null, null, null, {});
@@ -627,6 +628,7 @@ limitations under the License.
});
test('saveChangeEdit', done => {
element._projectLookup = {1: 'test'};
const change_num = '1';
const file_name = 'index.php';
const file_contents = '<?php';
@@ -636,17 +638,16 @@ limitations under the License.
sandbox.stub(element, 'getResponseObject')
.returns(Promise.resolve([change_num, file_name, file_contents]));
element._cache['/changes/' + change_num + '/edit/' + file_name] = {};
element.saveChangeEdit(change_num, file_name, file_contents).then(
() => {
assert.isTrue(element.send.calledWith('PUT',
'/changes/' + change_num + '/edit/' + file_name,
file_contents));
done();
}
);
element.saveChangeEdit(change_num, file_name, file_contents).then(() => {
assert.isTrue(element.send.calledWith('PUT',
'/changes/test~1/edit/' + file_name,
file_contents));
done();
});
});
test('putChangeCommitMessage', done => {
element._projectLookup = {1: 'test'};
const change_num = '1';
const message = 'this is a commit message';
sandbox.stub(element, 'send').returns(
@@ -655,42 +656,42 @@ limitations under the License.
sandbox.stub(element, 'getResponseObject')
.returns(Promise.resolve([change_num, message]));
element._cache['/changes/' + change_num + '/message'] = {};
element.putChangeCommitMessage(change_num, message).then(
() => {
assert.isTrue(element.send.calledWith('PUT',
'/changes/' + change_num + '/message', {message}));
done();
}
);
element.putChangeCommitMessage(change_num, message).then(() => {
assert.isTrue(element.send.calledWith('PUT',
'/changes/test~1/message', {message}));
done();
});
});
test('startWorkInProgress', () => {
sandbox.stub(element, 'send').returns(Promise.resolve('ok'));
sandbox.stub(element, 'getChangeURLAndSend')
.returns(Promise.resolve('ok'));
element.startWorkInProgress('42');
assert.isTrue(element.send.calledWith(
'POST', '/changes/42/wip', {}));
assert.isTrue(element.getChangeURLAndSend.calledWith(
'42', 'POST', null, '/wip', {}));
element.startWorkInProgress('42', 'revising...');
assert.isTrue(element.send.calledWith(
'POST', '/changes/42/wip', {message: 'revising...'}));
assert.isTrue(element.getChangeURLAndSend.calledWith(
'42', 'POST', null, '/wip', {message: 'revising...'}));
});
test('startReview', () => {
sandbox.stub(element, 'send').returns(Promise.resolve({}));
sandbox.stub(element, 'getChangeURLAndSend')
.returns(Promise.resolve({}));
element.startReview('42', {message: 'Please review.'});
assert.isTrue(element.send.calledWith(
'POST', '/changes/42/ready', {message: 'Please review.'}));
assert.isTrue(element.getChangeURLAndSend.calledWith(
'42', 'POST', null, '/ready', {message: 'Please review.'}));
});
test('deleteComment', done => {
sandbox.stub(element, 'send').returns(Promise.resolve());
sandbox.stub(element, 'getChangeURLAndSend').returns(Promise.resolve());
sandbox.stub(element, 'getResponseObject').returns('some response');
element.deleteComment('foo', 'bar', '01234', 'removal reason')
.then(response => {
assert.equal(response, 'some response');
done();
});
assert.isTrue(element.send.calledWith(
'POST', '/changes/foo/revisions/bar/comments/01234/delete',
assert.isTrue(element.getChangeURLAndSend.calledWith(
'foo', 'POST', 'bar', '/comments/01234/delete',
{reason: 'removal reason'}));
});
@@ -763,10 +764,9 @@ limitations under the License.
test('_getChangeDetail passes params to ETags decorator', () => {
const changeNum = 4321;
element._projectLookup[changeNum] = 'test';
const params = {foo: 'bar'};
const expectedUrl = element._urlWithParams(
element.getChangeActionURL(changeNum, null, '/detail'),
params);
const expectedUrl = '/changes/test~4321/detail?foo=bar';
sandbox.stub(element._etags, 'getOptions');
sandbox.stub(element._etags, 'collect');
return element._getChangeDetail(changeNum, params).then(() => {
@@ -858,5 +858,23 @@ limitations under the License.
assert.equal(element._projectLookup[1], 'test');
});
});
test('_getChangeURLAndFetch', () => {
element._projectLookup = {1: 'test'};
const fetchStub = sandbox.stub(element, 'fetchJSON')
.returns(Promise.resolve());
return element._getChangeURLAndFetch(1, '/test', 1).then(() => {
assert.isTrue(fetchStub.calledWith('/changes/test~1/revisions/1/test'));
});
});
test('getChangeURLAndSend', () => {
element._projectLookup = {1: 'test'};
const sendStub = sandbox.stub(element, 'send').returns(Promise.resolve());
return element.getChangeURLAndSend(1, 'POST', 1, '/test').then(() => {
assert.isTrue(sendStub.calledWith('POST',
'/changes/test~1/revisions/1/test'));
});
});
});
</script>