| // Copyright (C) 2014 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package com.google.gerrit.acceptance.edit; |
| |
| import static com.google.common.collect.Iterables.getOnlyElement; |
| import static com.google.common.truth.Truth.assertThat; |
| import static java.nio.charset.StandardCharsets.UTF_8; |
| import static java.util.concurrent.TimeUnit.MILLISECONDS; |
| import static java.util.concurrent.TimeUnit.SECONDS; |
| import static org.apache.http.HttpStatus.SC_CONFLICT; |
| import static org.apache.http.HttpStatus.SC_FORBIDDEN; |
| import static org.apache.http.HttpStatus.SC_NOT_FOUND; |
| import static org.apache.http.HttpStatus.SC_NO_CONTENT; |
| import static org.apache.http.HttpStatus.SC_OK; |
| |
| import com.google.common.base.Optional; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.Lists; |
| import com.google.gerrit.acceptance.AbstractDaemonTest; |
| import com.google.gerrit.acceptance.PushOneCommit; |
| import com.google.gerrit.acceptance.RestResponse; |
| import com.google.gerrit.acceptance.RestSession; |
| import com.google.gerrit.acceptance.TestProjectInput; |
| import com.google.gerrit.common.data.LabelType; |
| import com.google.gerrit.extensions.api.changes.ReviewInput; |
| import com.google.gerrit.extensions.client.InheritableBoolean; |
| import com.google.gerrit.extensions.client.ListChangesOption; |
| import com.google.gerrit.extensions.common.ApprovalInfo; |
| import com.google.gerrit.extensions.common.ChangeInfo; |
| import com.google.gerrit.extensions.common.ChangeMessageInfo; |
| import com.google.gerrit.extensions.common.EditInfo; |
| import com.google.gerrit.extensions.restapi.BinaryResult; |
| import com.google.gerrit.extensions.restapi.ResourceNotFoundException; |
| import com.google.gerrit.reviewdb.client.Change; |
| import com.google.gerrit.reviewdb.client.PatchSet; |
| import com.google.gerrit.reviewdb.server.ReviewDb; |
| import com.google.gerrit.server.change.ChangeEdits.EditMessage; |
| import com.google.gerrit.server.change.ChangeEdits.Post; |
| import com.google.gerrit.server.change.ChangeEdits.Put; |
| import com.google.gerrit.server.change.FileContentUtil; |
| import com.google.gerrit.server.edit.ChangeEdit; |
| import com.google.gerrit.server.edit.ChangeEditModifier; |
| import com.google.gerrit.server.edit.ChangeEditUtil; |
| import com.google.gerrit.server.edit.UnchangedCommitMessageException; |
| import com.google.gerrit.server.git.ProjectConfig; |
| import com.google.gerrit.server.project.InvalidChangeOperationException; |
| import com.google.gerrit.server.project.Util; |
| import com.google.gson.stream.JsonReader; |
| import com.google.gwtorm.server.SchemaFactory; |
| import com.google.inject.Inject; |
| |
| import org.apache.commons.codec.binary.StringUtils; |
| import org.eclipse.jgit.lib.ObjectId; |
| import org.eclipse.jgit.lib.PersonIdent; |
| import org.eclipse.jgit.lib.RefUpdate; |
| import org.joda.time.DateTime; |
| import org.joda.time.DateTimeUtils; |
| import org.joda.time.DateTimeUtils.MillisProvider; |
| import org.junit.After; |
| import org.junit.AfterClass; |
| import org.junit.Before; |
| import org.junit.BeforeClass; |
| import org.junit.Test; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Date; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.concurrent.atomic.AtomicLong; |
| |
| public class ChangeEditIT extends AbstractDaemonTest { |
| |
| private static final String FILE_NAME = "foo"; |
| private static final String FILE_NAME2 = "foo2"; |
| private static final String FILE_NAME3 = "foo3"; |
| private static final byte[] CONTENT_OLD = "bar".getBytes(UTF_8); |
| private static final byte[] CONTENT_NEW = "baz".getBytes(UTF_8); |
| private static final String CONTENT_NEW2_STR = "quxÄÜÖßµ"; |
| private static final byte[] CONTENT_NEW2 = CONTENT_NEW2_STR.getBytes(UTF_8); |
| |
| @Inject |
| private SchemaFactory<ReviewDb> reviewDbProvider; |
| |
| @Inject |
| ChangeEditUtil editUtil; |
| |
| @Inject |
| private ChangeEditModifier modifier; |
| |
| @Inject |
| private FileContentUtil fileUtil; |
| |
| private Change change; |
| private String changeId; |
| private Change change2; |
| private String changeId2; |
| private PatchSet ps; |
| private PatchSet ps2; |
| |
| @BeforeClass |
| public static void setTimeForTesting() { |
| final long clockStepMs = MILLISECONDS.convert(1, SECONDS); |
| final AtomicLong clockMs = new AtomicLong( |
| new DateTime(2009, 9, 30, 17, 0, 0).getMillis()); |
| DateTimeUtils.setCurrentMillisProvider(new MillisProvider() { |
| @Override |
| public long getMillis() { |
| return clockMs.getAndAdd(clockStepMs); |
| } |
| }); |
| } |
| |
| @AfterClass |
| public static void restoreTime() { |
| DateTimeUtils.setCurrentMillisSystem(); |
| } |
| |
| @Before |
| public void setUp() throws Exception { |
| db = reviewDbProvider.open(); |
| changeId = newChange(admin.getIdent()); |
| ps = getCurrentPatchSet(changeId); |
| amendChange(admin.getIdent(), changeId); |
| change = getChange(changeId); |
| assertThat(ps).isNotNull(); |
| changeId2 = newChange2(admin.getIdent()); |
| change2 = getChange(changeId2); |
| assertThat(change2).isNotNull(); |
| ps2 = getCurrentPatchSet(changeId2); |
| assertThat(ps2).isNotNull(); |
| } |
| |
| @After |
| public void cleanup() { |
| db.close(); |
| } |
| |
| @Test |
| public void deleteEdit() throws Exception { |
| assertThat(modifier.createEdit(change, ps)).isEqualTo(RefUpdate.Result.NEW); |
| assertThat( |
| modifier.modifyFile(editUtil.byChange(change).get(), FILE_NAME, |
| RestSession.newRawInput(CONTENT_NEW))).isEqualTo(RefUpdate.Result.FORCED); |
| editUtil.delete(editUtil.byChange(change).get()); |
| assertThat(editUtil.byChange(change).isPresent()).isFalse(); |
| } |
| |
| @Test |
| public void publishEdit() throws Exception { |
| assertThat(modifier.createEdit(change, getCurrentPatchSet(changeId))) |
| .isEqualTo(RefUpdate.Result.NEW); |
| assertThat( |
| modifier.modifyFile(editUtil.byChange(change).get(), FILE_NAME, |
| RestSession.newRawInput(CONTENT_NEW2))).isEqualTo(RefUpdate.Result.FORCED); |
| editUtil.publish(editUtil.byChange(change).get()); |
| Optional<ChangeEdit> edit = editUtil.byChange(change); |
| assertThat(edit.isPresent()).isFalse(); |
| assertChangeMessages(change, |
| ImmutableList.of("Uploaded patch set 1.", |
| "Uploaded patch set 2.", |
| "Patch Set 3: Published edit on patch set 2.")); |
| } |
| |
| @Test |
| public void publishEditRest() throws Exception { |
| PatchSet oldCurrentPatchSet = getCurrentPatchSet(changeId); |
| assertThat(modifier.createEdit(change, oldCurrentPatchSet)).isEqualTo( |
| RefUpdate.Result.NEW); |
| assertThat( |
| modifier.modifyFile(editUtil.byChange(change).get(), FILE_NAME, |
| RestSession.newRawInput(CONTENT_NEW))).isEqualTo(RefUpdate.Result.FORCED); |
| Optional<ChangeEdit> edit = editUtil.byChange(change); |
| RestResponse r = adminSession.post(urlPublish()); |
| assertThat(r.getStatusCode()).isEqualTo(SC_NO_CONTENT); |
| edit = editUtil.byChange(change); |
| assertThat(edit.isPresent()).isFalse(); |
| PatchSet newCurrentPatchSet = getCurrentPatchSet(changeId); |
| assertThat(newCurrentPatchSet.getId()).isNotEqualTo(oldCurrentPatchSet.getId()); |
| assertChangeMessages(change, |
| ImmutableList.of("Uploaded patch set 1.", |
| "Uploaded patch set 2.", |
| "Patch Set 3: Published edit on patch set 2.")); |
| } |
| |
| @Test |
| public void deleteEditRest() throws Exception { |
| assertThat(modifier.createEdit(change, ps)).isEqualTo(RefUpdate.Result.NEW); |
| assertThat( |
| modifier.modifyFile(editUtil.byChange(change).get(), FILE_NAME, |
| RestSession.newRawInput(CONTENT_NEW))).isEqualTo(RefUpdate.Result.FORCED); |
| Optional<ChangeEdit> edit = editUtil.byChange(change); |
| RestResponse r = adminSession.delete(urlEdit()); |
| assertThat(r.getStatusCode()).isEqualTo(SC_NO_CONTENT); |
| edit = editUtil.byChange(change); |
| assertThat(edit.isPresent()).isFalse(); |
| } |
| |
| @Test |
| public void publishEditRestWithoutCLA() throws Exception { |
| setUseContributorAgreements(InheritableBoolean.TRUE); |
| PatchSet oldCurrentPatchSet = getCurrentPatchSet(changeId); |
| assertThat(modifier.createEdit(change, oldCurrentPatchSet)).isEqualTo( |
| RefUpdate.Result.NEW); |
| assertThat( |
| modifier.modifyFile(editUtil.byChange(change).get(), FILE_NAME, |
| RestSession.newRawInput(CONTENT_NEW))).isEqualTo(RefUpdate.Result.FORCED); |
| RestResponse r = adminSession.post(urlPublish()); |
| assertThat(r.getStatusCode()).isEqualTo(SC_FORBIDDEN); |
| setUseContributorAgreements(InheritableBoolean.FALSE); |
| r = adminSession.post(urlPublish()); |
| assertThat(r.getStatusCode()).isEqualTo(SC_NO_CONTENT); |
| } |
| |
| @Test |
| public void rebaseEdit() throws Exception { |
| assertThat(modifier.createEdit(change, ps)).isEqualTo(RefUpdate.Result.NEW); |
| assertThat( |
| modifier.modifyFile(editUtil.byChange(change).get(), FILE_NAME, |
| RestSession.newRawInput(CONTENT_NEW))).isEqualTo(RefUpdate.Result.FORCED); |
| ChangeEdit edit = editUtil.byChange(change).get(); |
| PatchSet current = getCurrentPatchSet(changeId); |
| assertThat(edit.getBasePatchSet().getPatchSetId()).isEqualTo( |
| current.getPatchSetId() - 1); |
| Date beforeRebase = edit.getEditCommit().getCommitterIdent().getWhen(); |
| modifier.rebaseEdit(edit, current); |
| edit = editUtil.byChange(change).get(); |
| assertByteArray(fileUtil.getContent(projectCache.get(edit.getChange().getProject()), |
| ObjectId.fromString(edit.getRevision().get()), FILE_NAME), CONTENT_NEW); |
| assertByteArray(fileUtil.getContent(projectCache.get(edit.getChange().getProject()), |
| ObjectId.fromString(edit.getRevision().get()), FILE_NAME2), CONTENT_NEW2); |
| assertThat(edit.getBasePatchSet().getPatchSetId()).isEqualTo( |
| current.getPatchSetId()); |
| Date afterRebase = edit.getEditCommit().getCommitterIdent().getWhen(); |
| assertThat(beforeRebase.equals(afterRebase)).isFalse(); |
| } |
| |
| @Test |
| public void rebaseEditRest() throws Exception { |
| assertThat(modifier.createEdit(change, ps)).isEqualTo(RefUpdate.Result.NEW); |
| assertThat( |
| modifier.modifyFile(editUtil.byChange(change).get(), FILE_NAME, |
| RestSession.newRawInput(CONTENT_NEW))).isEqualTo(RefUpdate.Result.FORCED); |
| ChangeEdit edit = editUtil.byChange(change).get(); |
| PatchSet current = getCurrentPatchSet(changeId); |
| assertThat(edit.getBasePatchSet().getPatchSetId()).isEqualTo( |
| current.getPatchSetId() - 1); |
| Date beforeRebase = edit.getEditCommit().getCommitterIdent().getWhen(); |
| RestResponse r = adminSession.post(urlRebase()); |
| assertThat(r.getStatusCode()).isEqualTo(SC_NO_CONTENT); |
| edit = editUtil.byChange(change).get(); |
| assertByteArray(fileUtil.getContent(projectCache.get(edit.getChange().getProject()), |
| ObjectId.fromString(edit.getRevision().get()), FILE_NAME), CONTENT_NEW); |
| assertByteArray(fileUtil.getContent(projectCache.get(edit.getChange().getProject()), |
| ObjectId.fromString(edit.getRevision().get()), FILE_NAME2), CONTENT_NEW2); |
| assertThat(edit.getBasePatchSet().getPatchSetId()).isEqualTo( |
| current.getPatchSetId()); |
| Date afterRebase = edit.getEditCommit().getCommitterIdent().getWhen(); |
| assertThat(afterRebase).isNotEqualTo(beforeRebase); |
| } |
| |
| @Test |
| public void rebaseEditWithConflictsRest_Conflict() throws Exception { |
| PatchSet current = getCurrentPatchSet(changeId2); |
| assertThat(modifier.createEdit(change2, current)).isEqualTo(RefUpdate.Result.NEW); |
| assertThat( |
| modifier.modifyFile(editUtil.byChange(change2).get(), FILE_NAME, |
| RestSession.newRawInput(CONTENT_NEW))).isEqualTo(RefUpdate.Result.FORCED); |
| ChangeEdit edit = editUtil.byChange(change2).get(); |
| assertThat(edit.getBasePatchSet().getPatchSetId()).isEqualTo( |
| current.getPatchSetId()); |
| PushOneCommit push = |
| pushFactory.create(db, admin.getIdent(), testRepo, PushOneCommit.SUBJECT, FILE_NAME, |
| new String(CONTENT_NEW2), changeId2); |
| push.to("refs/for/master").assertOkStatus(); |
| RestResponse r = adminSession.post(urlRebase()); |
| assertThat(r.getStatusCode()).isEqualTo(SC_CONFLICT); |
| } |
| |
| @Test |
| public void updateExistingFile() throws Exception { |
| assertThat(modifier.createEdit(change, ps)).isEqualTo(RefUpdate.Result.NEW); |
| Optional<ChangeEdit> edit = editUtil.byChange(change); |
| assertThat(modifier.modifyFile(edit.get(), FILE_NAME, RestSession.newRawInput(CONTENT_NEW))) |
| .isEqualTo(RefUpdate.Result.FORCED); |
| edit = editUtil.byChange(change); |
| assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()), |
| ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_NEW); |
| editUtil.delete(edit.get()); |
| edit = editUtil.byChange(change); |
| assertThat(edit.isPresent()).isFalse(); |
| } |
| |
| @Test |
| @TestProjectInput(createEmptyCommit = false) |
| public void updateRootCommitMessage() throws Exception { |
| // Re-clone empty repo; TestRepository doesn't let us reset to unborn head. |
| testRepo = cloneProject(project); |
| changeId = newChange(admin.getIdent()); |
| change = getChange(changeId); |
| |
| assertThat(modifier.createEdit(change, getCurrentPatchSet(changeId))) |
| .isEqualTo(RefUpdate.Result.NEW); |
| Optional<ChangeEdit> edit = editUtil.byChange(change); |
| assertThat(edit.get().getEditCommit().getParentCount()).isEqualTo(0); |
| |
| String msg = String.format("New commit message\n\nChange-Id: %s\n", |
| change.getKey()); |
| assertThat(modifier.modifyMessage(edit.get(), msg)) |
| .isEqualTo(RefUpdate.Result.FORCED); |
| edit = editUtil.byChange(change); |
| assertThat(edit.get().getEditCommit().getFullMessage()).isEqualTo(msg); |
| } |
| |
| @Test |
| public void updateMessageNoChange() throws Exception { |
| assertThat(modifier.createEdit(change, getCurrentPatchSet(changeId))) |
| .isEqualTo(RefUpdate.Result.NEW); |
| Optional<ChangeEdit> edit = editUtil.byChange(change); |
| |
| exception.expect(UnchangedCommitMessageException.class); |
| exception.expectMessage( |
| "New commit message cannot be same as existing commit message"); |
| modifier.modifyMessage( |
| edit.get(), |
| edit.get().getEditCommit().getFullMessage()); |
| } |
| |
| @Test |
| public void updateMessage() throws Exception { |
| assertThat(modifier.createEdit(change, getCurrentPatchSet(changeId))) |
| .isEqualTo(RefUpdate.Result.NEW); |
| Optional<ChangeEdit> edit = editUtil.byChange(change); |
| assertUnchangedMessage(edit, edit.get().getEditCommit().getFullMessage()); |
| assertUnchangedMessage(edit, edit.get().getEditCommit().getFullMessage() + "\n\n"); |
| String msg = String.format("New commit message\n\nChange-Id: %s\n", |
| change.getKey()); |
| assertThat(modifier.modifyMessage(edit.get(), msg)).isEqualTo( |
| RefUpdate.Result.FORCED); |
| edit = editUtil.byChange(change); |
| assertThat(edit.get().getEditCommit().getFullMessage()).isEqualTo(msg); |
| |
| editUtil.publish(edit.get()); |
| assertThat(editUtil.byChange(change).isPresent()).isFalse(); |
| |
| ChangeInfo info = get(changeId, ListChangesOption.CURRENT_COMMIT, |
| ListChangesOption.CURRENT_REVISION); |
| assertThat(info.revisions.get(info.currentRevision).commit.message) |
| .isEqualTo(msg); |
| |
| assertChangeMessages(change, |
| ImmutableList.of("Uploaded patch set 1.", |
| "Uploaded patch set 2.", |
| "Patch Set 3: Commit message was updated.")); |
| } |
| |
| @Test |
| public void updateMessageRest() throws Exception { |
| assertThat(adminSession.get(urlEditMessage()).getStatusCode()) |
| .isEqualTo(SC_NOT_FOUND); |
| EditMessage.Input in = new EditMessage.Input(); |
| in.message = String.format("New commit message\n\n" + |
| CONTENT_NEW2_STR + "\n\nChange-Id: %s\n", |
| change.getKey()); |
| assertThat(adminSession.put(urlEditMessage(), in).getStatusCode()) |
| .isEqualTo(SC_NO_CONTENT); |
| RestResponse r = adminSession.getJsonAccept(urlEditMessage()); |
| assertThat(r.getStatusCode()).isEqualTo(SC_OK); |
| assertThat(readContentFromJson(r)).isEqualTo(in.message); |
| Optional<ChangeEdit> edit = editUtil.byChange(change); |
| assertThat(edit.get().getEditCommit().getFullMessage()) |
| .isEqualTo(in.message); |
| in.message = String.format("New commit message2\n\nChange-Id: %s\n", |
| change.getKey()); |
| assertThat(adminSession.put(urlEditMessage(), in).getStatusCode()) |
| .isEqualTo(SC_NO_CONTENT); |
| edit = editUtil.byChange(change); |
| assertThat(edit.get().getEditCommit().getFullMessage()) |
| .isEqualTo(in.message); |
| editUtil.publish(edit.get()); |
| assertChangeMessages(change, |
| ImmutableList.of("Uploaded patch set 1.", |
| "Uploaded patch set 2.", |
| "Patch Set 3: Commit message was updated.")); |
| } |
| |
| @Test |
| public void retrieveEdit() throws Exception { |
| RestResponse r = adminSession.get(urlEdit()); |
| assertThat(r.getStatusCode()).isEqualTo(SC_NO_CONTENT); |
| assertThat(modifier.createEdit(change, ps)).isEqualTo(RefUpdate.Result.NEW); |
| Optional<ChangeEdit> edit = editUtil.byChange(change); |
| assertThat(modifier.modifyFile(edit.get(), FILE_NAME, RestSession.newRawInput(CONTENT_NEW))) |
| .isEqualTo(RefUpdate.Result.FORCED); |
| edit = editUtil.byChange(change); |
| EditInfo info = toEditInfo(false); |
| assertThat(info.commit.commit).isEqualTo(edit.get().getRevision().get()); |
| assertThat(info.commit.parents).hasSize(1); |
| |
| edit = editUtil.byChange(change); |
| editUtil.delete(edit.get()); |
| |
| r = adminSession.get(urlEdit()); |
| assertThat(r.getStatusCode()).isEqualTo(SC_NO_CONTENT); |
| } |
| |
| @Test |
| public void retrieveFilesInEdit() throws Exception { |
| assertThat(modifier.createEdit(change, ps)).isEqualTo(RefUpdate.Result.NEW); |
| Optional<ChangeEdit> edit = editUtil.byChange(change); |
| assertThat(modifier.modifyFile(edit.get(), FILE_NAME, RestSession.newRawInput(CONTENT_NEW))) |
| .isEqualTo(RefUpdate.Result.FORCED); |
| |
| EditInfo info = toEditInfo(true); |
| assertThat(info.files).hasSize(2); |
| List<String> l = Lists.newArrayList(info.files.keySet()); |
| assertThat(l.get(0)).isEqualTo("/COMMIT_MSG"); |
| assertThat(l.get(1)).isEqualTo("foo"); |
| } |
| |
| @Test |
| public void deleteExistingFile() throws Exception { |
| assertThat(modifier.createEdit(change, ps)).isEqualTo(RefUpdate.Result.NEW); |
| Optional<ChangeEdit> edit = editUtil.byChange(change); |
| assertThat(modifier.deleteFile(edit.get(), FILE_NAME)).isEqualTo( |
| RefUpdate.Result.FORCED); |
| edit = editUtil.byChange(change); |
| exception.expect(ResourceNotFoundException.class); |
| fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()), |
| ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME); |
| } |
| |
| @Test |
| public void renameExistingFile() throws Exception { |
| assertThat(modifier.createEdit(change, ps)).isEqualTo(RefUpdate.Result.NEW); |
| Optional<ChangeEdit> edit = editUtil.byChange(change); |
| assertThat(modifier.renameFile(edit.get(), FILE_NAME, FILE_NAME3)) |
| .isEqualTo(RefUpdate.Result.FORCED); |
| edit = editUtil.byChange(change); |
| assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()), |
| ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME3), CONTENT_OLD); |
| exception.expect(ResourceNotFoundException.class); |
| fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()), |
| ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME); |
| } |
| |
| @Test |
| public void createEditByDeletingExistingFileRest() throws Exception { |
| RestResponse r = adminSession.delete(urlEditFile()); |
| assertThat(r.getStatusCode()).isEqualTo(SC_NO_CONTENT); |
| Optional<ChangeEdit> edit = editUtil.byChange(change); |
| exception.expect(ResourceNotFoundException.class); |
| fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()), |
| ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME); |
| } |
| |
| @Test |
| public void deletingNonExistingEditRest() throws Exception { |
| RestResponse r = adminSession.delete(urlEdit()); |
| assertThat(r.getStatusCode()).isEqualTo(SC_NOT_FOUND); |
| } |
| |
| @Test |
| public void deleteExistingFileRest() throws Exception { |
| assertThat(modifier.createEdit(change, ps)).isEqualTo(RefUpdate.Result.NEW); |
| assertThat(adminSession.delete(urlEditFile()).getStatusCode()).isEqualTo( |
| SC_NO_CONTENT); |
| Optional<ChangeEdit> edit = editUtil.byChange(change); |
| exception.expect(ResourceNotFoundException.class); |
| fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()), |
| ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME); |
| } |
| |
| @Test |
| public void restoreDeletedFileInPatchSet() throws Exception { |
| assertThat(modifier.createEdit(change2, ps2)).isEqualTo( |
| RefUpdate.Result.NEW); |
| Optional<ChangeEdit> edit = editUtil.byChange(change2); |
| assertThat(modifier.restoreFile(edit.get(), FILE_NAME)).isEqualTo( |
| RefUpdate.Result.FORCED); |
| edit = editUtil.byChange(change2); |
| assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()), |
| ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_OLD); |
| } |
| |
| @Test |
| public void revertChanges() throws Exception { |
| assertThat(modifier.createEdit(change2, ps2)).isEqualTo( |
| RefUpdate.Result.NEW); |
| Optional<ChangeEdit> edit = editUtil.byChange(change2); |
| assertThat(modifier.restoreFile(edit.get(), FILE_NAME)).isEqualTo( |
| RefUpdate.Result.FORCED); |
| edit = editUtil.byChange(change2); |
| assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()), |
| ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_OLD); |
| assertThat( |
| modifier.modifyFile(editUtil.byChange(change2).get(), FILE_NAME, |
| RestSession.newRawInput(CONTENT_NEW))).isEqualTo(RefUpdate.Result.FORCED); |
| edit = editUtil.byChange(change2); |
| assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()), |
| ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_NEW); |
| assertThat(modifier.restoreFile(edit.get(), FILE_NAME)).isEqualTo( |
| RefUpdate.Result.FORCED); |
| edit = editUtil.byChange(change2); |
| assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()), |
| ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_OLD); |
| editUtil.delete(edit.get()); |
| } |
| |
| @Test |
| public void renameFileRest() throws Exception { |
| assertThat(modifier.createEdit(change, ps)).isEqualTo(RefUpdate.Result.NEW); |
| Post.Input in = new Post.Input(); |
| in.oldPath = FILE_NAME; |
| in.newPath = FILE_NAME3; |
| assertThat(adminSession.post(urlEdit(), in).getStatusCode()).isEqualTo( |
| SC_NO_CONTENT); |
| Optional<ChangeEdit> edit = editUtil.byChange(change); |
| assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()), |
| ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME3), CONTENT_OLD); |
| exception.expect(ResourceNotFoundException.class); |
| fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()), |
| ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME); |
| } |
| |
| @Test |
| public void restoreDeletedFileInPatchSetRest() throws Exception { |
| Post.Input in = new Post.Input(); |
| in.restorePath = FILE_NAME; |
| assertThat(adminSession.post(urlEdit2(), in).getStatusCode()).isEqualTo( |
| SC_NO_CONTENT); |
| Optional<ChangeEdit> edit = editUtil.byChange(change2); |
| assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()), |
| ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_OLD); |
| } |
| |
| @Test |
| public void amendExistingFile() throws Exception { |
| assertThat(modifier.createEdit(change, ps)).isEqualTo(RefUpdate.Result.NEW); |
| Optional<ChangeEdit> edit = editUtil.byChange(change); |
| assertThat(modifier.modifyFile(edit.get(), FILE_NAME, RestSession.newRawInput(CONTENT_NEW))) |
| .isEqualTo(RefUpdate.Result.FORCED); |
| edit = editUtil.byChange(change); |
| assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()), |
| ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_NEW); |
| assertThat(modifier.modifyFile(edit.get(), FILE_NAME, RestSession.newRawInput(CONTENT_NEW2))) |
| .isEqualTo(RefUpdate.Result.FORCED); |
| edit = editUtil.byChange(change); |
| assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()), |
| ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_NEW2); |
| } |
| |
| @Test |
| public void createAndChangeEditInOneRequestRest() throws Exception { |
| Put.Input in = new Put.Input(); |
| in.content = RestSession.newRawInput(CONTENT_NEW); |
| assertThat(adminSession.putRaw(urlEditFile(), in.content).getStatusCode()) |
| .isEqualTo(SC_NO_CONTENT); |
| Optional<ChangeEdit> edit = editUtil.byChange(change); |
| assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()), |
| ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_NEW); |
| in.content = RestSession.newRawInput(CONTENT_NEW2); |
| assertThat(adminSession.putRaw(urlEditFile(), in.content).getStatusCode()) |
| .isEqualTo(SC_NO_CONTENT); |
| edit = editUtil.byChange(change); |
| assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()), |
| ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_NEW2); |
| } |
| |
| @Test |
| public void changeEditRest() throws Exception { |
| assertThat(modifier.createEdit(change, ps)).isEqualTo(RefUpdate.Result.NEW); |
| Put.Input in = new Put.Input(); |
| in.content = RestSession.newRawInput(CONTENT_NEW); |
| assertThat(adminSession.putRaw(urlEditFile(), in.content).getStatusCode()) |
| .isEqualTo(SC_NO_CONTENT); |
| Optional<ChangeEdit> edit = editUtil.byChange(change); |
| assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()), |
| ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_NEW); |
| } |
| |
| @Test |
| public void emptyPutRequest() throws Exception { |
| assertThat(modifier.createEdit(change, ps)).isEqualTo(RefUpdate.Result.NEW); |
| assertThat(adminSession.put(urlEditFile()).getStatusCode()).isEqualTo( |
| SC_NO_CONTENT); |
| Optional<ChangeEdit> edit = editUtil.byChange(change); |
| assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()), |
| ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), "".getBytes()); |
| } |
| |
| @Test |
| public void createEmptyEditRest() throws Exception { |
| assertThat(adminSession.post(urlEdit()).getStatusCode()).isEqualTo( |
| SC_NO_CONTENT); |
| Optional<ChangeEdit> edit = editUtil.byChange(change); |
| assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()), |
| ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME), CONTENT_OLD); |
| } |
| |
| @Test |
| public void getFileContentRest() throws Exception { |
| Put.Input in = new Put.Input(); |
| in.content = RestSession.newRawInput(CONTENT_NEW); |
| assertThat(adminSession.putRaw(urlEditFile(), in.content).getStatusCode()) |
| .isEqualTo(SC_NO_CONTENT); |
| Optional<ChangeEdit> edit = editUtil.byChange(change); |
| assertThat(modifier.modifyFile(edit.get(), FILE_NAME, RestSession.newRawInput(CONTENT_NEW2))) |
| .isEqualTo(RefUpdate.Result.FORCED); |
| edit = editUtil.byChange(change); |
| RestResponse r = adminSession.getJsonAccept(urlEditFile()); |
| assertThat(r.getStatusCode()).isEqualTo(SC_OK); |
| assertThat(readContentFromJson(r)).isEqualTo( |
| StringUtils.newStringUtf8(CONTENT_NEW2)); |
| } |
| |
| @Test |
| public void getFileNotFoundRest() throws Exception { |
| assertThat(modifier.createEdit(change, ps)).isEqualTo(RefUpdate.Result.NEW); |
| assertThat(adminSession.delete(urlEditFile()).getStatusCode()).isEqualTo( |
| SC_NO_CONTENT); |
| Optional<ChangeEdit> edit = editUtil.byChange(change); |
| RestResponse r = adminSession.get(urlEditFile()); |
| assertThat(r.getStatusCode()).isEqualTo(SC_NO_CONTENT); |
| exception.expect(ResourceNotFoundException.class); |
| fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()), |
| ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME); |
| } |
| |
| @Test |
| public void addNewFile() throws Exception { |
| assertThat(modifier.createEdit(change, ps)).isEqualTo(RefUpdate.Result.NEW); |
| Optional<ChangeEdit> edit = editUtil.byChange(change); |
| assertThat(modifier.modifyFile(edit.get(), FILE_NAME2, RestSession.newRawInput(CONTENT_NEW))) |
| .isEqualTo(RefUpdate.Result.FORCED); |
| edit = editUtil.byChange(change); |
| assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()), |
| ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME2), CONTENT_NEW); |
| } |
| |
| @Test |
| public void addNewFileAndAmend() throws Exception { |
| assertThat(modifier.createEdit(change, ps)).isEqualTo(RefUpdate.Result.NEW); |
| Optional<ChangeEdit> edit = editUtil.byChange(change); |
| assertThat(modifier.modifyFile(edit.get(), FILE_NAME2, RestSession.newRawInput(CONTENT_NEW))) |
| .isEqualTo(RefUpdate.Result.FORCED); |
| edit = editUtil.byChange(change); |
| assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()), |
| ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME2), CONTENT_NEW); |
| assertThat(modifier.modifyFile(edit.get(), FILE_NAME2, RestSession.newRawInput(CONTENT_NEW2))) |
| .isEqualTo(RefUpdate.Result.FORCED); |
| edit = editUtil.byChange(change); |
| assertByteArray(fileUtil.getContent(projectCache.get(edit.get().getChange().getProject()), |
| ObjectId.fromString(edit.get().getRevision().get()), FILE_NAME2), CONTENT_NEW2); |
| } |
| |
| @Test |
| public void writeNoChanges() throws Exception { |
| assertThat(modifier.createEdit(change, ps)).isEqualTo(RefUpdate.Result.NEW); |
| exception.expect(InvalidChangeOperationException.class); |
| exception.expectMessage("no changes were made"); |
| modifier.modifyFile( |
| editUtil.byChange(change).get(), |
| FILE_NAME, |
| RestSession.newRawInput(CONTENT_OLD)); |
| } |
| |
| @Test |
| public void editCommitMessageCopiesLabelScores() throws Exception { |
| String cr = "Code-Review"; |
| ProjectConfig cfg = projectCache.checkedGet(project).getConfig(); |
| LabelType codeReview = Util.codeReview(); |
| codeReview.setCopyAllScoresIfNoCodeChange(true); |
| cfg.getLabelSections().put(cr, codeReview); |
| saveProjectConfig(project, cfg); |
| |
| String changeId = change.getKey().get(); |
| ReviewInput r = new ReviewInput(); |
| r.labels = ImmutableMap.<String, Short> of(cr, (short) 1); |
| gApi.changes() |
| .id(changeId) |
| .revision(change.currentPatchSetId().get()) |
| .review(r); |
| |
| assertThat(modifier.createEdit(change, getCurrentPatchSet(changeId))) |
| .isEqualTo(RefUpdate.Result.NEW); |
| Optional<ChangeEdit> edit = editUtil.byChange(change); |
| String newSubj = "New commit message"; |
| String newMsg = newSubj + "\n\nChange-Id: " + changeId + "\n"; |
| assertThat(modifier.modifyMessage(edit.get(), newMsg)) |
| .isEqualTo(RefUpdate.Result.FORCED); |
| edit = editUtil.byChange(change); |
| editUtil.publish(edit.get()); |
| |
| ChangeInfo info = get(changeId); |
| assertThat(info.subject).isEqualTo(newSubj); |
| List<ApprovalInfo> approvals = info.labels.get(cr).all; |
| assertThat(approvals).hasSize(1); |
| assertThat(approvals.get(0).value).isEqualTo(1); |
| } |
| |
| private void assertUnchangedMessage(Optional<ChangeEdit> edit, String message) |
| throws Exception { |
| exception.expect(UnchangedCommitMessageException.class); |
| exception.expectMessage( |
| "New commit message cannot be same as existing commit message"); |
| modifier.modifyMessage(edit.get(), message); |
| } |
| |
| @Test |
| public void testHasEditPredicate() throws Exception { |
| assertThat(modifier.createEdit(change, ps)).isEqualTo(RefUpdate.Result.NEW); |
| assertThat(queryEdits()).hasSize(1); |
| |
| PatchSet current = getCurrentPatchSet(changeId2); |
| assertThat(modifier.createEdit(change2, current)).isEqualTo(RefUpdate.Result.NEW); |
| assertThat( |
| modifier.modifyFile(editUtil.byChange(change2).get(), FILE_NAME, |
| RestSession.newRawInput(CONTENT_NEW))).isEqualTo(RefUpdate.Result.FORCED); |
| assertThat(queryEdits()).hasSize(2); |
| |
| assertThat( |
| modifier.modifyFile(editUtil.byChange(change).get(), FILE_NAME, |
| RestSession.newRawInput(CONTENT_NEW))).isEqualTo(RefUpdate.Result.FORCED); |
| editUtil.delete(editUtil.byChange(change).get()); |
| assertThat(queryEdits()).hasSize(1); |
| |
| editUtil.publish(editUtil.byChange(change2).get()); |
| assertThat(queryEdits()).hasSize(0); |
| |
| setApiUser(user); |
| assertThat(modifier.createEdit(change, ps)).isEqualTo(RefUpdate.Result.NEW); |
| assertThat(queryEdits()).hasSize(1); |
| |
| setApiUser(admin); |
| assertThat(queryEdits()).hasSize(0); |
| } |
| |
| private List<ChangeInfo> queryEdits() throws Exception { |
| return query("project:{" + project.get() + "} has:edit"); |
| } |
| |
| private String newChange(PersonIdent ident) throws Exception { |
| PushOneCommit push = |
| pushFactory.create(db, ident, testRepo, PushOneCommit.SUBJECT, FILE_NAME, |
| new String(CONTENT_OLD, UTF_8)); |
| return push.to("refs/for/master").getChangeId(); |
| } |
| |
| private String amendChange(PersonIdent ident, String changeId) throws Exception { |
| PushOneCommit push = |
| pushFactory.create(db, ident, testRepo, PushOneCommit.SUBJECT, FILE_NAME2, |
| new String(CONTENT_NEW2, UTF_8), changeId); |
| return push.to("refs/for/master").getChangeId(); |
| } |
| |
| private String newChange2(PersonIdent ident) throws Exception { |
| PushOneCommit push = |
| pushFactory.create(db, ident, testRepo, PushOneCommit.SUBJECT, FILE_NAME, |
| new String(CONTENT_OLD, UTF_8)); |
| return push.rm("refs/for/master").getChangeId(); |
| } |
| |
| private Change getChange(String changeId) throws Exception { |
| return getOnlyElement(queryProvider.get().byKeyPrefix(changeId)).change(); |
| } |
| |
| private PatchSet getCurrentPatchSet(String changeId) throws Exception { |
| return db.patchSets() |
| .get(getChange(changeId).currentPatchSetId()); |
| } |
| |
| private static void assertByteArray(BinaryResult result, byte[] expected) |
| throws Exception { |
| ByteArrayOutputStream os = new ByteArrayOutputStream(); |
| result.writeTo(os); |
| assertThat(os.toByteArray()).isEqualTo(expected); |
| } |
| |
| private String urlEdit() { |
| return "/changes/" |
| + change.getChangeId() |
| + "/edit"; |
| } |
| |
| private String urlEdit2() { |
| return "/changes/" |
| + change2.getChangeId() |
| + "/edit/"; |
| } |
| |
| private String urlEditMessage() { |
| return "/changes/" |
| + change.getChangeId() |
| + "/edit:message"; |
| } |
| |
| private String urlEditFile() { |
| return urlEdit() |
| + "/" |
| + FILE_NAME; |
| } |
| |
| private String urlGetFiles() { |
| return urlEdit() |
| + "?list"; |
| } |
| |
| private String urlPublish() { |
| return "/changes/" |
| + change.getChangeId() |
| + "/edit:publish"; |
| } |
| |
| private String urlRebase() { |
| return "/changes/" |
| + change.getChangeId() |
| + "/edit:rebase"; |
| } |
| |
| private EditInfo toEditInfo(boolean files) throws IOException { |
| RestResponse r = adminSession.get(files ? urlGetFiles() : urlEdit()); |
| assertThat(r.getStatusCode()).isEqualTo(SC_OK); |
| return newGson().fromJson(r.getReader(), EditInfo.class); |
| } |
| |
| private String readContentFromJson(RestResponse r) throws IOException { |
| JsonReader jsonReader = new JsonReader(r.getReader()); |
| jsonReader.setLenient(true); |
| return newGson().fromJson(jsonReader, String.class); |
| } |
| |
| private void assertChangeMessages(Change c, List<String> expectedMessages) |
| throws Exception { |
| ChangeInfo ci = get(c.getId().toString()); |
| assertThat(ci.messages).isNotNull(); |
| assertThat(ci.messages).hasSize(expectedMessages.size()); |
| List<String> actualMessages = new ArrayList<>(); |
| Iterator<ChangeMessageInfo> it = ci.messages.iterator(); |
| while (it.hasNext()) { |
| actualMessages.add(it.next().message); |
| } |
| assertThat(actualMessages) |
| .containsExactlyElementsIn(expectedMessages) |
| .inOrder(); |
| } |
| } |