| // Copyright (C) 2020 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.testsuite.change; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.permissionKey; |
| import static com.google.gerrit.extensions.common.testing.CommitInfoSubject.assertThat; |
| import static com.google.gerrit.extensions.common.testing.CommitInfoSubject.hasCommit; |
| import static com.google.gerrit.extensions.common.testing.DiffInfoSubject.assertThat; |
| import static com.google.gerrit.extensions.restapi.testing.BinaryResultSubject.assertThat; |
| import static com.google.gerrit.testing.GerritJUnit.assertThrows; |
| import static com.google.gerrit.truth.MapSubject.assertThatMap; |
| import static com.google.gerrit.truth.OptionalSubject.assertThat; |
| |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.truth.Correspondence; |
| import com.google.gerrit.acceptance.AbstractDaemonTest; |
| import com.google.gerrit.acceptance.testsuite.account.AccountOperations; |
| import com.google.gerrit.acceptance.testsuite.account.TestAccount; |
| import com.google.gerrit.acceptance.testsuite.project.ProjectOperations; |
| import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations; |
| import com.google.gerrit.entities.Account; |
| import com.google.gerrit.entities.Change; |
| import com.google.gerrit.entities.PatchSet; |
| import com.google.gerrit.entities.Permission; |
| import com.google.gerrit.entities.Project; |
| import com.google.gerrit.extensions.api.changes.ReviewInput; |
| import com.google.gerrit.extensions.client.ChangeKind; |
| import com.google.gerrit.extensions.common.ChangeInfo; |
| import com.google.gerrit.extensions.common.ChangeType; |
| import com.google.gerrit.extensions.common.CommitInfo; |
| import com.google.gerrit.extensions.common.DiffInfo; |
| import com.google.gerrit.extensions.common.FileInfo; |
| import com.google.gerrit.extensions.common.RevisionInfo; |
| import com.google.gerrit.extensions.restapi.BinaryResult; |
| import com.google.gerrit.extensions.restapi.RestApiException; |
| import com.google.gerrit.truth.NullAwareCorrespondence; |
| import com.google.gerrit.truth.OptionalSubject; |
| import com.google.inject.Inject; |
| import java.util.Map; |
| import org.eclipse.jgit.lib.ObjectId; |
| import org.eclipse.jgit.lib.PersonIdent; |
| import org.junit.Test; |
| |
| public class ChangeOperationsImplTest extends AbstractDaemonTest { |
| |
| @Inject private ChangeOperations changeOperations; |
| @Inject private ProjectOperations projectOperations; |
| @Inject private AccountOperations accountOperations; |
| @Inject private RequestScopeOperations requestScopeOperations; |
| |
| @Test |
| public void changeCanBeCreatedWithoutSpecifyingAnyParameters() throws Exception { |
| Change.Id numericChangeId = changeOperations.newChange().create(); |
| |
| ChangeInfo change = getChangeFromServer(numericChangeId); |
| assertThat(change._number).isEqualTo(numericChangeId.get()); |
| assertThat(change.changeId).isNotEmpty(); |
| } |
| |
| @Test |
| public void changeCanBeCreatedEvenWithRequestScopeOfArbitraryUser() throws Exception { |
| Account.Id user = accountOperations.newAccount().create(); |
| |
| requestScopeOperations.setApiUser(user); |
| Change.Id numericChangeId = changeOperations.newChange().create(); |
| |
| ChangeInfo change = getChangeFromServer(numericChangeId); |
| assertThat(change._number).isEqualTo(numericChangeId.get()); |
| } |
| |
| @Test |
| public void twoChangesWithoutAnyParametersDoNotClash() { |
| Change.Id changeId1 = changeOperations.newChange().create(); |
| Change.Id changeId2 = changeOperations.newChange().create(); |
| |
| TestChange change1 = changeOperations.change(changeId1).get(); |
| TestChange change2 = changeOperations.change(changeId2).get(); |
| assertThat(change1.numericChangeId()).isNotEqualTo(change2.numericChangeId()); |
| assertThat(change1.changeId()).isNotEqualTo(change2.changeId()); |
| } |
| |
| @Test |
| public void twoSubsequentlyCreatedChangesDoNotDependOnEachOther() throws Exception { |
| Change.Id changeId1 = changeOperations.newChange().create(); |
| Change.Id changeId2 = changeOperations.newChange().create(); |
| |
| ChangeInfo change1 = getChangeFromServer(changeId1); |
| ChangeInfo change2 = getChangeFromServer(changeId2); |
| CommitInfo currentPatchsetCommit1 = change1.revisions.get(change1.currentRevision).commit; |
| CommitInfo currentPatchsetCommit2 = change2.revisions.get(change2.currentRevision).commit; |
| assertThat(currentPatchsetCommit1) |
| .parents() |
| .comparingElementsUsing(hasCommit()) |
| .doesNotContain(currentPatchsetCommit2.commit); |
| assertThat(currentPatchsetCommit2) |
| .parents() |
| .comparingElementsUsing(hasCommit()) |
| .doesNotContain(currentPatchsetCommit1.commit); |
| } |
| |
| @Test |
| public void createdChangeHasAtLeastOnePatchset() throws Exception { |
| Change.Id changeId = changeOperations.newChange().create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| assertThatMap(change.revisions).size().isAtLeast(1); |
| } |
| |
| @Test |
| public void createdChangeIsInSpecifiedProject() throws Exception { |
| Project.NameKey project = projectOperations.newProject().create(); |
| Change.Id changeId = changeOperations.newChange().project(project).create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| assertThat(change.project).isEqualTo(project.get()); |
| } |
| |
| @Test |
| public void changeCanBeCreatedInEmptyRepository() throws Exception { |
| Project.NameKey project = projectOperations.newProject().noEmptyCommit().create(); |
| Change.Id changeId = changeOperations.newChange().project(project).create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| assertThat(change.project).isEqualTo(project.get()); |
| } |
| |
| @Test |
| public void createdChangeHasSpecifiedTargetBranch() throws Exception { |
| Project.NameKey project = projectOperations.newProject().branches("test-branch").create(); |
| Change.Id changeId = |
| changeOperations.newChange().project(project).branch("test-branch").create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| assertThat(change.branch).isEqualTo("test-branch"); |
| } |
| |
| @Test |
| public void createdChangeHasDefaultGroupsByDefault() throws Exception { |
| Project.NameKey project = projectOperations.newProject().branches("test-branch").create(); |
| Change.Id changeId = |
| changeOperations.newChange().project(project).branch("test-branch").create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| assertThat(getGroups(project, changeId)).containsExactly(change.currentRevision); |
| } |
| |
| @Test |
| public void createdChangeHasDefaultGroupsIfBranchTipIsSpecifiedAsParent() throws Exception { |
| Project.NameKey project = projectOperations.newProject().branches("test-branch").create(); |
| |
| Change.Id changeId = |
| changeOperations |
| .newChange() |
| .project(project) |
| .childOf() |
| .tipOfBranch("refs/heads/test-branch") |
| .create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| assertThat(getGroups(project, changeId)).containsExactly(change.currentRevision); |
| } |
| |
| @Test |
| public void createdChangeHasSameGroupsAsOpenParentChange() throws Exception { |
| Project.NameKey project = projectOperations.newProject().create(); |
| |
| Change.Id parentChangeId = changeOperations.newChange().project(project).create(); |
| |
| ChangeInfo parentChange = getChangeFromServer(parentChangeId); |
| ImmutableList<String> parentGroups = getGroups(project, parentChangeId); |
| assertThat(parentGroups).containsExactly(parentChange.currentRevision); |
| |
| Change.Id changeId = |
| changeOperations.newChange().project(project).childOf().change(parentChangeId).create(); |
| |
| assertThat(getGroups(project, changeId)).isEqualTo(parentGroups); |
| } |
| |
| @Test |
| public void createdChangeHasDefaultGroupsIfClosedChangeIsSpecifiedAsParent() throws Exception { |
| Project.NameKey project = projectOperations.newProject().create(); |
| |
| Change.Id parentChangeId = changeOperations.newChange().project(project).create(); |
| gApi.changes().id(parentChangeId.get()).current().review(ReviewInput.approve()); |
| gApi.changes().id(parentChangeId.get()).current().submit(); |
| |
| Change.Id changeId = |
| changeOperations.newChange().project(project).childOf().change(parentChangeId).create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| assertThat(getGroups(project, changeId)).containsExactly(change.currentRevision); |
| } |
| |
| @Test |
| public void createdChangeHasSameGroupsAsPatchSetOfOpenParentChange() throws Exception { |
| Project.NameKey project = projectOperations.newProject().create(); |
| |
| Change.Id parentChangeId = changeOperations.newChange().project(project).create(); |
| TestPatchset parentPatchset = changeOperations.change(parentChangeId).currentPatchset().get(); |
| changeOperations.change(parentChangeId).newPatchset().create(); |
| |
| ImmutableList<String> parentGroups = getGroups(project, parentPatchset.patchsetId()); |
| assertThat(parentGroups).containsExactly(parentPatchset.commitId().name()); |
| |
| Change.Id changeId = |
| changeOperations |
| .newChange() |
| .project(project) |
| .childOf() |
| .patchset(parentPatchset.patchsetId()) |
| .create(); |
| |
| assertThat(getGroups(project, changeId)).isEqualTo(parentGroups); |
| } |
| |
| @Test |
| public void createdChangeHasDefaultGroupsIfPatchSetOfClosedChangeIsSpecifiedAsParent() |
| throws Exception { |
| Project.NameKey project = projectOperations.newProject().create(); |
| |
| Change.Id parentChangeId = changeOperations.newChange().project(project).create(); |
| TestPatchset parentPatchset = changeOperations.change(parentChangeId).currentPatchset().get(); |
| changeOperations.change(parentChangeId).newPatchset().create(); |
| gApi.changes().id(parentChangeId.get()).current().review(ReviewInput.approve()); |
| gApi.changes().id(parentChangeId.get()).current().submit(); |
| |
| Change.Id changeId = |
| changeOperations |
| .newChange() |
| .project(project) |
| .childOf() |
| .patchset(parentPatchset.patchsetId()) |
| .create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| assertThat(getGroups(project, changeId)).containsExactly(change.currentRevision); |
| } |
| |
| @Test |
| public void createdChangeHasDefaultGroupsIfCommitIsSpecifiedAsParent() throws Exception { |
| Project.NameKey project = projectOperations.newProject().create(); |
| |
| // Currently, the easiest way to create a commit is by creating another change. |
| Change.Id anotherChangeId = changeOperations.newChange().project(project).create(); |
| ObjectId parentCommitId = |
| changeOperations.change(anotherChangeId).currentPatchset().get().commitId(); |
| |
| Change.Id changeId = |
| changeOperations.newChange().project(project).childOf().commit(parentCommitId).create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| assertThat(getGroups(project, changeId)).containsExactly(change.currentRevision); |
| } |
| |
| @Test |
| public void createdChangeUsesTipOfTargetBranchAsParentByDefault() throws Exception { |
| Project.NameKey project = projectOperations.newProject().branches("test-branch").create(); |
| ObjectId parentCommitId = projectOperations.project(project).getHead("test-branch").getId(); |
| Change.Id changeId = |
| changeOperations.newChange().project(project).branch("test-branch").create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| CommitInfo currentPatchsetCommit = change.revisions.get(change.currentRevision).commit; |
| assertThat(currentPatchsetCommit) |
| .parents() |
| .onlyElement() |
| .commit() |
| .isEqualTo(parentCommitId.name()); |
| } |
| |
| @Test |
| public void createdChangeUsesSpecifiedBranchTipAsParent() throws Exception { |
| Project.NameKey project = projectOperations.newProject().branches("test-branch").create(); |
| |
| Change.Id changeId = |
| changeOperations |
| .newChange() |
| .project(project) |
| .childOf() |
| .tipOfBranch("refs/heads/test-branch") |
| .create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| CommitInfo currentPatchsetCommit = change.revisions.get(change.currentRevision).commit; |
| ObjectId parentCommitId = projectOperations.project(project).getHead("test-branch").getId(); |
| assertThat(currentPatchsetCommit) |
| .parents() |
| .onlyElement() |
| .commit() |
| .isEqualTo(parentCommitId.name()); |
| } |
| |
| @Test |
| public void specifiedParentBranchMayHaveShortName() throws Exception { |
| Project.NameKey project = projectOperations.newProject().branches("test-branch").create(); |
| |
| Change.Id changeId = |
| changeOperations.newChange().project(project).childOf().tipOfBranch("test-branch").create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| CommitInfo currentPatchsetCommit = change.revisions.get(change.currentRevision).commit; |
| ObjectId parentCommitId = projectOperations.project(project).getHead("test-branch").getId(); |
| assertThat(currentPatchsetCommit) |
| .parents() |
| .onlyElement() |
| .commit() |
| .isEqualTo(parentCommitId.name()); |
| } |
| |
| @Test |
| public void specifiedParentBranchMustExist() { |
| IllegalStateException exception = |
| assertThrows( |
| IllegalStateException.class, |
| () -> |
| changeOperations.newChange().childOf().tipOfBranch("not-existing-branch").create()); |
| assertThat(exception).hasMessageThat().ignoringCase().contains("parent"); |
| } |
| |
| @Test |
| public void createdChangeUsesSpecifiedChangeAsParent() throws Exception { |
| Change.Id parentChangeId = changeOperations.newChange().create(); |
| |
| Change.Id changeId = changeOperations.newChange().childOf().change(parentChangeId).create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| CommitInfo currentPatchsetCommit = change.revisions.get(change.currentRevision).commit; |
| ObjectId parentCommitId = |
| changeOperations.change(parentChangeId).currentPatchset().get().commitId(); |
| assertThat(currentPatchsetCommit) |
| .parents() |
| .onlyElement() |
| .commit() |
| .isEqualTo(parentCommitId.name()); |
| } |
| |
| @Test |
| public void specifiedParentChangeMustExist() { |
| IllegalStateException exception = |
| assertThrows( |
| IllegalStateException.class, |
| () -> changeOperations.newChange().childOf().change(Change.id(987654321)).create()); |
| assertThat(exception).hasMessageThat().ignoringCase().contains("parent"); |
| } |
| |
| @Test |
| public void createdChangeUsesSpecifiedPatchsetAsParent() throws Exception { |
| Change.Id parentChangeId = changeOperations.newChange().create(); |
| TestPatchset parentPatchset = changeOperations.change(parentChangeId).currentPatchset().get(); |
| |
| Change.Id changeId = |
| changeOperations.newChange().childOf().patchset(parentPatchset.patchsetId()).create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| CommitInfo currentPatchsetCommit = change.revisions.get(change.currentRevision).commit; |
| assertThat(currentPatchsetCommit) |
| .parents() |
| .onlyElement() |
| .commit() |
| .isEqualTo(parentPatchset.commitId().name()); |
| } |
| |
| @Test |
| public void changeOfSpecifiedParentPatchsetMustExist() { |
| IllegalStateException exception = |
| assertThrows( |
| IllegalStateException.class, |
| () -> |
| changeOperations |
| .newChange() |
| .childOf() |
| .patchset(PatchSet.id(Change.id(987654321), 1)) |
| .create()); |
| assertThat(exception).hasMessageThat().ignoringCase().contains("parent"); |
| } |
| |
| @Test |
| public void specifiedParentPatchsetMustExist() { |
| Change.Id parentChangeId = changeOperations.newChange().create(); |
| |
| IllegalStateException exception = |
| assertThrows( |
| IllegalStateException.class, |
| () -> |
| changeOperations |
| .newChange() |
| .childOf() |
| .patchset(PatchSet.id(parentChangeId, 1000)) |
| .create()); |
| assertThat(exception).hasMessageThat().ignoringCase().contains("parent"); |
| } |
| |
| @Test |
| public void createdChangeUsesSpecifiedCommitAsParent() throws Exception { |
| // Currently, the easiest way to create a commit is by creating another change. |
| Change.Id anotherChangeId = changeOperations.newChange().create(); |
| ObjectId parentCommitId = |
| changeOperations.change(anotherChangeId).currentPatchset().get().commitId(); |
| |
| Change.Id changeId = changeOperations.newChange().childOf().commit(parentCommitId).create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| CommitInfo currentPatchsetCommit = change.revisions.get(change.currentRevision).commit; |
| assertThat(currentPatchsetCommit) |
| .parents() |
| .onlyElement() |
| .commit() |
| .isEqualTo(parentCommitId.name()); |
| } |
| |
| @Test |
| public void specifiedParentCommitMustExist() { |
| IllegalStateException exception = |
| assertThrows( |
| IllegalStateException.class, |
| () -> |
| changeOperations |
| .newChange() |
| .childOf() |
| .commit(ObjectId.fromString("0123456789012345678901234567890123456789")) |
| .create()); |
| assertThat(exception).hasMessageThat().ignoringCase().contains("parent"); |
| } |
| |
| @Test |
| public void createdChangeUsesSpecifiedChangesInGivenOrderAsParents() throws Exception { |
| Change.Id parent1ChangeId = changeOperations.newChange().create(); |
| Change.Id parent2ChangeId = changeOperations.newChange().create(); |
| |
| Change.Id changeId = |
| changeOperations |
| .newChange() |
| .mergeOf() |
| .change(parent1ChangeId) |
| .and() |
| .change(parent2ChangeId) |
| .create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| CommitInfo currentPatchsetCommit = change.revisions.get(change.currentRevision).commit; |
| ObjectId parent1CommitId = |
| changeOperations.change(parent1ChangeId).currentPatchset().get().commitId(); |
| ObjectId parent2CommitId = |
| changeOperations.change(parent2ChangeId).currentPatchset().get().commitId(); |
| assertThat(currentPatchsetCommit) |
| .parents() |
| .comparingElementsUsing(hasSha1()) |
| .containsExactly(parent1CommitId.name(), parent2CommitId.name()) |
| .inOrder(); |
| } |
| |
| @Test |
| public void createdChangeUsesMergedParentsAsBaseCommit() throws Exception { |
| Change.Id parent1ChangeId = |
| changeOperations.newChange().file("file1").content("Line 1").create(); |
| Change.Id parent2ChangeId = |
| changeOperations.newChange().file("file2").content("Some other content").create(); |
| |
| Change.Id changeId = |
| changeOperations |
| .newChange() |
| .mergeOf() |
| .change(parent1ChangeId) |
| .and() |
| .change(parent2ChangeId) |
| .create(); |
| |
| PatchSet.Id patchsetId = changeOperations.change(changeId).currentPatchset().get().patchsetId(); |
| BinaryResult file1Content = getFileContent(changeId, patchsetId, "file1"); |
| assertThat(file1Content).asString().isEqualTo("Line 1"); |
| BinaryResult file2Content = getFileContent(changeId, patchsetId, "file2"); |
| assertThat(file2Content).asString().isEqualTo("Some other content"); |
| } |
| |
| @Test |
| public void mergeConflictsOfParentsAreReported() { |
| Change.Id parent1ChangeId = |
| changeOperations.newChange().file("file1").content("Content 1").create(); |
| Change.Id parent2ChangeId = |
| changeOperations.newChange().file("file1").content("Content 2").create(); |
| |
| IllegalStateException exception = |
| assertThrows( |
| IllegalStateException.class, |
| () -> |
| changeOperations |
| .newChange() |
| .mergeOf() |
| .change(parent1ChangeId) |
| .and() |
| .change(parent2ChangeId) |
| .create()); |
| |
| assertThat(exception).hasMessageThat().ignoringCase().contains("conflict"); |
| } |
| |
| @Test |
| public void mergeConflictsCanBeAvoidedByUsingTheFirstParentAsBase() throws Exception { |
| Change.Id parent1ChangeId = |
| changeOperations.newChange().file("file1").content("Content 1").create(); |
| Change.Id parent2ChangeId = |
| changeOperations.newChange().file("file1").content("Content 2").create(); |
| |
| Change.Id changeId = |
| changeOperations |
| .newChange() |
| .mergeOfButBaseOnFirst() |
| .change(parent1ChangeId) |
| .and() |
| .change(parent2ChangeId) |
| .create(); |
| |
| PatchSet.Id patchsetId = changeOperations.change(changeId).currentPatchset().get().patchsetId(); |
| BinaryResult file1Content = getFileContent(changeId, patchsetId, "file1"); |
| assertThat(file1Content).asString().isEqualTo("Content 1"); |
| } |
| |
| @Test |
| public void createdChangeHasAllParentsEvenWhenBasedOnFirst() throws Exception { |
| Change.Id parent1ChangeId = changeOperations.newChange().create(); |
| Change.Id parent2ChangeId = changeOperations.newChange().create(); |
| |
| Change.Id changeId = |
| changeOperations |
| .newChange() |
| .mergeOfButBaseOnFirst() |
| .change(parent1ChangeId) |
| .and() |
| .change(parent2ChangeId) |
| .create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| CommitInfo currentPatchsetCommit = change.revisions.get(change.currentRevision).commit; |
| ObjectId parent1CommitId = |
| changeOperations.change(parent1ChangeId).currentPatchset().get().commitId(); |
| ObjectId parent2CommitId = |
| changeOperations.change(parent2ChangeId).currentPatchset().get().commitId(); |
| assertThat(currentPatchsetCommit) |
| .parents() |
| .comparingElementsUsing(hasSha1()) |
| .containsExactly(parent1CommitId.name(), parent2CommitId.name()) |
| .inOrder(); |
| } |
| |
| @Test |
| public void automaticMergeOfMoreThanTwoParentsIsNotPossible() { |
| Change.Id parent1ChangeId = |
| changeOperations.newChange().file("file1").content("Content 1").create(); |
| Change.Id parent2ChangeId = |
| changeOperations.newChange().file("file2").content("Content 2").create(); |
| Change.Id parent3ChangeId = |
| changeOperations.newChange().file("file3").content("Content 3").create(); |
| |
| IllegalStateException exception = |
| assertThrows( |
| IllegalStateException.class, |
| () -> |
| changeOperations |
| .newChange() |
| .mergeOf() |
| .change(parent1ChangeId) |
| .followedBy() |
| .change(parent2ChangeId) |
| .and() |
| .change(parent3ChangeId) |
| .create()); |
| |
| assertThat(exception).hasMessageThat().ignoringCase().contains("conflict"); |
| } |
| |
| @Test |
| public void createdChangeCanHaveMoreThanTwoParentsWhenBasedOnFirst() throws Exception { |
| Change.Id parent1ChangeId = |
| changeOperations.newChange().file("file1").content("Content 1").create(); |
| Change.Id parent2ChangeId = |
| changeOperations.newChange().file("file2").content("Content 2").create(); |
| Change.Id parent3ChangeId = |
| changeOperations.newChange().file("file3").content("Content 3").create(); |
| |
| Change.Id changeId = |
| changeOperations |
| .newChange() |
| .mergeOfButBaseOnFirst() |
| .change(parent1ChangeId) |
| .followedBy() |
| .change(parent2ChangeId) |
| .and() |
| .change(parent3ChangeId) |
| .create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| CommitInfo currentPatchsetCommit = change.revisions.get(change.currentRevision).commit; |
| ObjectId parent1CommitId = |
| changeOperations.change(parent1ChangeId).currentPatchset().get().commitId(); |
| ObjectId parent2CommitId = |
| changeOperations.change(parent2ChangeId).currentPatchset().get().commitId(); |
| ObjectId parent3CommitId = |
| changeOperations.change(parent3ChangeId).currentPatchset().get().commitId(); |
| assertThat(currentPatchsetCommit) |
| .parents() |
| .comparingElementsUsing(hasSha1()) |
| .containsExactly(parent1CommitId.name(), parent2CommitId.name(), parent3CommitId.name()) |
| .inOrder(); |
| } |
| |
| @Test |
| public void changeBasedOnParentMayHaveAdditionalFileModifications() throws Exception { |
| Change.Id parentChangeId = |
| changeOperations |
| .newChange() |
| .file("file1") |
| .content("Content 1") |
| .file("file2") |
| .content("Content 2") |
| .create(); |
| |
| Change.Id changeId = |
| changeOperations |
| .newChange() |
| .childOf() |
| .change(parentChangeId) |
| .file("file1") |
| .content("Different content") |
| .create(); |
| |
| PatchSet.Id patchsetId = changeOperations.change(changeId).currentPatchset().get().patchsetId(); |
| BinaryResult file1Content = getFileContent(changeId, patchsetId, "file1"); |
| assertThat(file1Content).asString().isEqualTo("Different content"); |
| BinaryResult file2Content = getFileContent(changeId, patchsetId, "file2"); |
| assertThat(file2Content).asString().isEqualTo("Content 2"); |
| } |
| |
| @Test |
| public void changeFromMergedParentsMayHaveAdditionalFileModifications() throws Exception { |
| Change.Id parent1ChangeId = |
| changeOperations.newChange().file("file1").content("Content 1").create(); |
| Change.Id parent2ChangeId = |
| changeOperations.newChange().file("file2").content("Content 2").create(); |
| |
| Change.Id changeId = |
| changeOperations |
| .newChange() |
| .mergeOf() |
| .change(parent1ChangeId) |
| .and() |
| .change(parent2ChangeId) |
| .file("file1") |
| .content("Different content") |
| .create(); |
| |
| PatchSet.Id patchsetId = changeOperations.change(changeId).currentPatchset().get().patchsetId(); |
| BinaryResult file1Content = getFileContent(changeId, patchsetId, "file1"); |
| assertThat(file1Content).asString().isEqualTo("Different content"); |
| BinaryResult file2Content = getFileContent(changeId, patchsetId, "file2"); |
| assertThat(file2Content).asString().isEqualTo("Content 2"); |
| } |
| |
| @Test |
| public void changeBasedOnFirstOfMultipleParentsMayHaveAdditionalFileModifications() |
| throws Exception { |
| Change.Id parent1ChangeId = |
| changeOperations.newChange().file("file1").content("Content 1").create(); |
| Change.Id parent2ChangeId = changeOperations.newChange().create(); |
| |
| Change.Id changeId = |
| changeOperations |
| .newChange() |
| .mergeOfButBaseOnFirst() |
| .change(parent1ChangeId) |
| .and() |
| .change(parent2ChangeId) |
| .file("file1") |
| .content("Different content") |
| .create(); |
| |
| PatchSet.Id patchsetId = changeOperations.change(changeId).currentPatchset().get().patchsetId(); |
| BinaryResult file1Content = getFileContent(changeId, patchsetId, "file1"); |
| assertThat(file1Content).asString().isEqualTo("Different content"); |
| } |
| |
| @Test |
| public void createdChangeHasSpecifiedOwner() throws Exception { |
| Account.Id changeOwner = accountOperations.newAccount().create(); |
| Change.Id changeId = changeOperations.newChange().owner(changeOwner).create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| assertThat(change.owner._accountId).isEqualTo(changeOwner.get()); |
| } |
| |
| @Test |
| public void changeOwnerDoesNotNeedAnyPermissionsForChangeCreation() throws Exception { |
| Account.Id changeOwner = accountOperations.newAccount().create(); |
| Project.NameKey project = projectOperations.newProject().branches("test-branch").create(); |
| // Remove any read and push permissions which might potentially exist. Without read, users |
| // shouldn't be able to do anything. The newly created project should only inherit from |
| // All-Projects. |
| projectOperations |
| .project(project) |
| .forUpdate() |
| .remove(permissionKey(Permission.READ).ref("refs/heads/test-branch")) |
| .remove(permissionKey(Permission.PUSH).ref("refs/heads/test-branch")) |
| .update(); |
| projectOperations |
| .allProjectsForUpdate() |
| .remove(permissionKey(Permission.READ).ref("refs/heads/test-branch")) |
| .remove(permissionKey(Permission.PUSH).ref("refs/heads/test-branch")) |
| .update(); |
| |
| Change.Id changeId = |
| changeOperations |
| .newChange() |
| .owner(changeOwner) |
| .branch("test-branch") |
| .project(project) |
| .create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| assertThat(change.owner._accountId).isEqualTo(changeOwner.get()); |
| } |
| |
| @Test |
| public void createdChangeHasOwnerAsAuthor() throws Exception { |
| Change.Id changeId = changeOperations.newChange().create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| TestAccount changeOwner = accountOperations.account(Account.id(change.owner._accountId)).get(); |
| RevisionInfo revision = change.revisions.get(change.currentRevision); |
| assertThat(revision.commit.author.name).isEqualTo(changeOwner.fullname().get()); |
| assertThat(revision.commit.author.email).isEqualTo(changeOwner.preferredEmail().get()); |
| } |
| |
| @Test |
| public void createdChangeHasSpecifiedOwnerAsAuthor() throws Exception { |
| String changeOwnerName = "Change Owner"; |
| String changeOwnerEmail = "change-owner@example.com"; |
| Account.Id changeOwner = |
| accountOperations |
| .newAccount() |
| .fullname(changeOwnerName) |
| .preferredEmail(changeOwnerEmail) |
| .create(); |
| Change.Id changeId = changeOperations.newChange().owner(changeOwner).create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| assertThat(change.owner._accountId).isEqualTo(changeOwner.get()); |
| RevisionInfo revision = change.revisions.get(change.currentRevision); |
| assertThat(revision.commit.author.name).isEqualTo(changeOwnerName); |
| assertThat(revision.commit.author.email).isEqualTo(changeOwnerEmail); |
| } |
| |
| @Test |
| public void createdChangeHasSpecifiedAuthor() throws Exception { |
| String authorName = "Author"; |
| String authorEmail = "author@example.com"; |
| Account.Id author = |
| accountOperations.newAccount().fullname(authorName).preferredEmail(authorEmail).create(); |
| Change.Id changeId = changeOperations.newChange().author(author).create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| assertThat(change.owner._accountId).isNotEqualTo(author.get()); |
| RevisionInfo revision = change.revisions.get(change.currentRevision); |
| assertThat(revision.commit.author.name).isEqualTo(authorName); |
| assertThat(revision.commit.author.email).isEqualTo(authorEmail); |
| } |
| |
| @Test |
| public void createdChangeHasSpecifiedAuthorIdent() throws Exception { |
| PersonIdent authorIdent = new PersonIdent("Author", "author@example.com"); |
| Change.Id changeId = changeOperations.newChange().authorIdent(authorIdent).create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| RevisionInfo revision = change.revisions.get(change.currentRevision); |
| assertThat(revision.commit.author.name).isEqualTo(authorIdent.getName()); |
| assertThat(revision.commit.author.email).isEqualTo(authorIdent.getEmailAddress()); |
| } |
| |
| @Test |
| public void changeCannotBeCreatedWithAuthorAndAuthorIdent() throws Exception { |
| Account.Id author = accountOperations.newAccount().create(); |
| PersonIdent authorIdent = new PersonIdent("Author", "author@example.com"); |
| |
| IllegalStateException exception = |
| assertThrows( |
| IllegalStateException.class, |
| () -> changeOperations.newChange().author(author).authorIdent(authorIdent).create()); |
| assertThat(exception) |
| .hasMessageThat() |
| .isEqualTo("author and authorIdent cannot be set together"); |
| } |
| |
| @Test |
| public void createdChangeHasOwnerAsCommitter() throws Exception { |
| Change.Id changeId = changeOperations.newChange().create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| TestAccount changeOwner = accountOperations.account(Account.id(change.owner._accountId)).get(); |
| RevisionInfo revision = change.revisions.get(change.currentRevision); |
| assertThat(revision.commit.committer.name).isEqualTo(changeOwner.fullname().get()); |
| assertThat(revision.commit.committer.email).isEqualTo(changeOwner.preferredEmail().get()); |
| } |
| |
| @Test |
| public void createdChangeHasSpecifiedOwnerAsCommitter() throws Exception { |
| String changeOwnerName = "Change Owner"; |
| String changeOwnerEmail = "change-owner@example.com"; |
| Account.Id changeOwner = |
| accountOperations |
| .newAccount() |
| .fullname(changeOwnerName) |
| .preferredEmail(changeOwnerEmail) |
| .create(); |
| Change.Id changeId = changeOperations.newChange().owner(changeOwner).create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| assertThat(change.owner._accountId).isEqualTo(changeOwner.get()); |
| RevisionInfo revision = change.revisions.get(change.currentRevision); |
| assertThat(revision.commit.committer.name).isEqualTo(changeOwnerName); |
| assertThat(revision.commit.committer.email).isEqualTo(changeOwnerEmail); |
| } |
| |
| @Test |
| public void createdChangeHasSpecifiedCommitter() throws Exception { |
| String committerName = "Committer"; |
| String committerEmail = "committer@example.com"; |
| Account.Id committer = |
| accountOperations |
| .newAccount() |
| .fullname(committerName) |
| .preferredEmail(committerEmail) |
| .create(); |
| Change.Id changeId = changeOperations.newChange().committer(committer).create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| assertThat(change.owner._accountId).isNotEqualTo(committer.get()); |
| RevisionInfo revision = change.revisions.get(change.currentRevision); |
| assertThat(revision.commit.committer.name).isEqualTo(committerName); |
| assertThat(revision.commit.committer.email).isEqualTo(committerEmail); |
| } |
| |
| @Test |
| public void createdChangeHasSpecifiedCommitterIdent() throws Exception { |
| PersonIdent committerIdent = new PersonIdent("Committer", "committer@example.com"); |
| Change.Id changeId = changeOperations.newChange().committerIdent(committerIdent).create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| RevisionInfo revision = change.revisions.get(change.currentRevision); |
| assertThat(revision.commit.committer.name).isEqualTo(committerIdent.getName()); |
| assertThat(revision.commit.committer.email).isEqualTo(committerIdent.getEmailAddress()); |
| } |
| |
| @Test |
| public void changeCannotBeCreatedWithCommitterAndCommitterIdent() throws Exception { |
| Account.Id committer = accountOperations.newAccount().create(); |
| PersonIdent committerIdent = new PersonIdent("Committer", "committer@example.com"); |
| |
| IllegalStateException exception = |
| assertThrows( |
| IllegalStateException.class, |
| () -> |
| changeOperations |
| .newChange() |
| .committer(committer) |
| .committerIdent(committerIdent) |
| .create()); |
| assertThat(exception) |
| .hasMessageThat() |
| .isEqualTo("committer and committerIdent cannot be set together"); |
| } |
| |
| @Test |
| public void createdChangeHasSpecifiedTopic() throws Exception { |
| Change.Id changeId = changeOperations.newChange().topic("test-topic").create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| assertThat(change.topic).isEqualTo("test-topic"); |
| } |
| |
| @Test |
| public void createdChangeHasSpecifiedApprovals() throws Exception { |
| Change.Id changeId = |
| changeOperations.newChange().approvals(ImmutableMap.of("Code-Review", (short) 1)).create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| assertThat(change.labels).hasSize(1); |
| assertThat(change.labels.get("Code-Review").recommended._accountId) |
| .isEqualTo(change.owner._accountId); |
| } |
| |
| @Test |
| public void createdChangeHasSpecifiedCommitMessage() throws Exception { |
| Change.Id changeId = |
| changeOperations |
| .newChange() |
| .commitMessage("Summary line\n\nDetailed description.") |
| .create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| CommitInfo currentPatchsetCommit = change.revisions.get(change.currentRevision).commit; |
| assertThat(currentPatchsetCommit).message().startsWith("Summary line\n\nDetailed description."); |
| } |
| |
| @Test |
| public void changeCannotBeCreatedWithoutCommitMessage() { |
| assertThrows( |
| IllegalStateException.class, () -> changeOperations.newChange().commitMessage("").create()); |
| } |
| |
| @Test |
| public void commitMessageOfCreatedChangeAutomaticallyGetsChangeId() throws Exception { |
| Change.Id changeId = |
| changeOperations |
| .newChange() |
| .commitMessage("Summary line\n\nDetailed description.") |
| .create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| CommitInfo currentPatchsetCommit = change.revisions.get(change.currentRevision).commit; |
| assertThat(currentPatchsetCommit).message().contains("Change-Id:"); |
| } |
| |
| @Test |
| public void changeIdSpecifiedInCommitMessageIsKeptForCreatedChange() throws Exception { |
| Change.Id changeId = |
| changeOperations |
| .newChange() |
| .commitMessage("Summary line\n\nChange-Id: I0123456789012345678901234567890123456789") |
| .create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| CommitInfo currentPatchsetCommit = change.revisions.get(change.currentRevision).commit; |
| assertThat(currentPatchsetCommit) |
| .message() |
| .contains("Change-Id: I0123456789012345678901234567890123456789"); |
| assertThat(change.changeId).isEqualTo("I0123456789012345678901234567890123456789"); |
| } |
| |
| @Test |
| public void createdChangeHasSpecifiedFiles() throws Exception { |
| Change.Id changeId = |
| changeOperations |
| .newChange() |
| .file("file1") |
| .content("Line 1") |
| .file("path/to/file2.txt") |
| .content("Line one") |
| .create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| Map<String, FileInfo> files = change.revisions.get(change.currentRevision).files; |
| assertThatMap(files).keys().containsExactly("file1", "path/to/file2.txt"); |
| BinaryResult fileContent1 = gApi.changes().id(changeId.get()).current().file("file1").content(); |
| assertThat(fileContent1).asString().isEqualTo("Line 1"); |
| BinaryResult fileContent2 = |
| gApi.changes().id(changeId.get()).current().file("path/to/file2.txt").content(); |
| assertThat(fileContent2).asString().isEqualTo("Line one"); |
| } |
| |
| @Test |
| public void existingChangeCanBeCheckedForExistence() { |
| Change.Id changeId = changeOperations.newChange().create(); |
| |
| boolean exists = changeOperations.change(changeId).exists(); |
| |
| assertThat(exists).isTrue(); |
| } |
| |
| @Test |
| public void notExistingChangeCanBeCheckedForExistence() { |
| Change.Id changeId = Change.id(123456789); |
| |
| boolean exists = changeOperations.change(changeId).exists(); |
| |
| assertThat(exists).isFalse(); |
| } |
| |
| @Test |
| public void retrievingNotExistingChangeFails() { |
| Change.Id changeId = Change.id(123456789); |
| assertThrows(IllegalStateException.class, () -> changeOperations.change(changeId).get()); |
| } |
| |
| @Test |
| public void numericChangeIdOfExistingChangeCanBeRetrieved() { |
| Change.Id changeId = changeOperations.newChange().create(); |
| |
| TestChange change = changeOperations.change(changeId).get(); |
| assertThat(change.numericChangeId()).isEqualTo(changeId); |
| } |
| |
| @Test |
| public void changeIdOfExistingChangeCanBeRetrieved() { |
| Change.Id changeId = |
| changeOperations |
| .newChange() |
| .commitMessage("Summary line\n\nChange-Id: I0123456789012345678901234567890123456789") |
| .create(); |
| |
| TestChange change = changeOperations.change(changeId).get(); |
| assertThat(change.changeId()).isEqualTo("I0123456789012345678901234567890123456789"); |
| } |
| |
| @Test |
| public void currentPatchsetOfExistingChangeCanBeRetrieved() throws Exception { |
| Change.Id changeId = changeOperations.newChange().create(); |
| |
| TestPatchset patchset = changeOperations.change(changeId).currentPatchset().get(); |
| |
| ChangeInfo expectedChange = getChangeFromServer(changeId); |
| String expectedCommitId = expectedChange.currentRevision; |
| int expectedPatchsetNumber = expectedChange.revisions.get(expectedCommitId)._number; |
| assertThat(patchset.commitId()).isEqualTo(ObjectId.fromString(expectedCommitId)); |
| assertThat(patchset.patchsetId()).isEqualTo(PatchSet.id(changeId, expectedPatchsetNumber)); |
| } |
| |
| @Test |
| public void earlierPatchsetOfExistingChangeCanBeRetrieved() { |
| Change.Id changeId = changeOperations.newChange().create(); |
| PatchSet.Id earlierPatchsetId = |
| changeOperations.change(changeId).currentPatchset().get().patchsetId(); |
| PatchSet.Id currentPatchsetId = changeOperations.change(changeId).newPatchset().create(); |
| |
| TestPatchset earlierPatchset = |
| changeOperations.change(changeId).patchset(earlierPatchsetId).get(); |
| |
| assertThat(earlierPatchset.patchsetId()).isEqualTo(earlierPatchsetId); |
| assertThat(earlierPatchset.patchsetId()).isNotEqualTo(currentPatchsetId); |
| } |
| |
| @Test |
| public void newPatchsetCanBeCreatedWithoutSpecifyingAnyParameters() throws Exception { |
| Change.Id changeId = changeOperations.newChange().create(); |
| ChangeInfo unmodifiedChange = getChangeFromServer(changeId); |
| int originalPatchsetCount = unmodifiedChange.revisions.size(); |
| |
| PatchSet.Id patchsetId = changeOperations.change(changeId).newPatchset().create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| assertThatMap(change.revisions).hasSize(originalPatchsetCount + 1); |
| RevisionInfo currentRevision = change.revisions.get(change.currentRevision); |
| assertThat(currentRevision._number).isEqualTo(patchsetId.get()); |
| } |
| |
| @Test |
| public void newPatchsetIsCopyOfPreviousPatchsetByDefault() throws Exception { |
| Change.Id changeId = changeOperations.newChange().create(); |
| |
| PatchSet.Id patchsetId = changeOperations.change(changeId).newPatchset().create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| RevisionInfo patchsetRevision = getRevision(change, patchsetId); |
| assertThat(patchsetRevision.kind).isEqualTo(ChangeKind.NO_CHANGE); |
| } |
| |
| @Test |
| public void newPatchsetCanHaveDifferentUploader() throws Exception { |
| Account.Id changeOwner = accountOperations.newAccount().create(); |
| Change.Id changeId = changeOperations.newChange().owner(changeOwner).create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| RevisionInfo currentPatchsetRevision = change.revisions.get(change.currentRevision); |
| assertThat(currentPatchsetRevision.uploader._accountId).isEqualTo(changeOwner.get()); |
| |
| Account.Id newUploader = accountOperations.newAccount().create(); |
| changeOperations.change(changeId).newPatchset().uploader(newUploader).create(); |
| |
| change = getChangeFromServer(changeId); |
| currentPatchsetRevision = change.revisions.get(change.currentRevision); |
| assertThat(currentPatchsetRevision.uploader._accountId).isEqualTo(newUploader.get()); |
| } |
| |
| @Test |
| public void createdPatchsetPreviousAuthorAsAuthor() throws Exception { |
| String authorName = "Author"; |
| String authorEmail = "author@example.com"; |
| Account.Id author = |
| accountOperations.newAccount().fullname(authorName).preferredEmail(authorEmail).create(); |
| Change.Id changeId = changeOperations.newChange().author(author).create(); |
| ChangeInfo change = getChangeFromServer(changeId); |
| RevisionInfo revision = change.revisions.get(change.currentRevision); |
| assertThat(revision.commit.author.name).isEqualTo(authorName); |
| assertThat(revision.commit.author.email).isEqualTo(authorEmail); |
| |
| changeOperations.change(changeId).newPatchset().create(); |
| change = getChangeFromServer(changeId); |
| revision = change.revisions.get(change.currentRevision); |
| assertThat(revision.commit.author.name).isEqualTo(authorName); |
| assertThat(revision.commit.author.email).isEqualTo(authorEmail); |
| } |
| |
| @Test |
| public void createdPatchsetHasSpecifiedAuthor() throws Exception { |
| Change.Id changeId = changeOperations.newChange().create(); |
| |
| String authorName = "Author"; |
| String authorEmail = "author@example.com"; |
| Account.Id author = |
| accountOperations.newAccount().fullname(authorName).preferredEmail(authorEmail).create(); |
| changeOperations.change(changeId).newPatchset().author(author).create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| assertThat(change.owner._accountId).isNotEqualTo(author.get()); |
| RevisionInfo revision = change.revisions.get(change.currentRevision); |
| assertThat(revision.commit.author.name).isEqualTo(authorName); |
| assertThat(revision.commit.author.email).isEqualTo(authorEmail); |
| } |
| |
| @Test |
| public void createdPatchsetHasSpecifiedAuthorIdent() throws Exception { |
| Change.Id changeId = changeOperations.newChange().create(); |
| |
| PersonIdent authorIdent = new PersonIdent("Author", "author@example.com"); |
| changeOperations.change(changeId).newPatchset().authorIdent(authorIdent).create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| RevisionInfo revision = change.revisions.get(change.currentRevision); |
| assertThat(revision.commit.author.name).isEqualTo(authorIdent.getName()); |
| assertThat(revision.commit.author.email).isEqualTo(authorIdent.getEmailAddress()); |
| } |
| |
| @Test |
| public void patchsetCannotBeCreatedWithAuthorAndAuthorIdent() throws Exception { |
| Change.Id changeId = changeOperations.newChange().create(); |
| |
| Account.Id author = accountOperations.newAccount().create(); |
| PersonIdent authorIdent = new PersonIdent("Author", "author@example.com"); |
| |
| IllegalStateException exception = |
| assertThrows( |
| IllegalStateException.class, |
| () -> |
| changeOperations |
| .change(changeId) |
| .newPatchset() |
| .author(author) |
| .authorIdent(authorIdent) |
| .create()); |
| assertThat(exception) |
| .hasMessageThat() |
| .isEqualTo("author and authorIdent cannot be set together"); |
| } |
| |
| @Test |
| public void createdPatchsetPreviousCommitterAsCommitter() throws Exception { |
| String committerName = "Committer"; |
| String committerEmail = "committer@example.com"; |
| Account.Id committer = |
| accountOperations |
| .newAccount() |
| .fullname(committerName) |
| .preferredEmail(committerEmail) |
| .create(); |
| Change.Id changeId = changeOperations.newChange().committer(committer).create(); |
| ChangeInfo change = getChangeFromServer(changeId); |
| RevisionInfo revision = change.revisions.get(change.currentRevision); |
| assertThat(revision.commit.committer.name).isEqualTo(committerName); |
| assertThat(revision.commit.committer.email).isEqualTo(committerEmail); |
| |
| changeOperations.change(changeId).newPatchset().create(); |
| change = getChangeFromServer(changeId); |
| revision = change.revisions.get(change.currentRevision); |
| assertThat(revision.commit.committer.name).isEqualTo(committerName); |
| assertThat(revision.commit.committer.email).isEqualTo(committerEmail); |
| } |
| |
| @Test |
| public void createdPatchsetHasSpecifiedCommitter() throws Exception { |
| Change.Id changeId = changeOperations.newChange().create(); |
| |
| String committerName = "Committer"; |
| String committerEmail = "committer@example.com"; |
| Account.Id committer = |
| accountOperations |
| .newAccount() |
| .fullname(committerName) |
| .preferredEmail(committerEmail) |
| .create(); |
| changeOperations.change(changeId).newPatchset().committer(committer).create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| assertThat(change.owner._accountId).isNotEqualTo(committer.get()); |
| RevisionInfo revision = change.revisions.get(change.currentRevision); |
| assertThat(revision.commit.committer.name).isEqualTo(committerName); |
| assertThat(revision.commit.committer.email).isEqualTo(committerEmail); |
| } |
| |
| @Test |
| public void createdPatchsetHasSpecifiedCommitterIdent() throws Exception { |
| Change.Id changeId = changeOperations.newChange().create(); |
| |
| PersonIdent committerIdent = new PersonIdent("Committer", "committer@example.com"); |
| changeOperations.change(changeId).newPatchset().committerIdent(committerIdent).create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| RevisionInfo revision = change.revisions.get(change.currentRevision); |
| assertThat(revision.commit.committer.name).isEqualTo(committerIdent.getName()); |
| assertThat(revision.commit.committer.email).isEqualTo(committerIdent.getEmailAddress()); |
| } |
| |
| @Test |
| public void patchsetCannotBeCreatedWithCommitterAndCommitterIdent() throws Exception { |
| Change.Id changeId = changeOperations.newChange().create(); |
| |
| Account.Id committer = accountOperations.newAccount().create(); |
| PersonIdent committerIdent = new PersonIdent("Committer", "committer@example.com"); |
| |
| IllegalStateException exception = |
| assertThrows( |
| IllegalStateException.class, |
| () -> |
| changeOperations |
| .change(changeId) |
| .newPatchset() |
| .committer(committer) |
| .committerIdent(committerIdent) |
| .create()); |
| assertThat(exception) |
| .hasMessageThat() |
| .isEqualTo("committer and committerIdent cannot be set together"); |
| } |
| |
| @Test |
| public void newPatchsetCanHaveUpdatedCommitMessage() throws Exception { |
| Change.Id changeId = changeOperations.newChange().commitMessage("Old message").create(); |
| |
| changeOperations.change(changeId).newPatchset().commitMessage("New message").create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| CommitInfo currentPatchsetCommit = change.revisions.get(change.currentRevision).commit; |
| assertThat(currentPatchsetCommit).message().startsWith("New message"); |
| } |
| |
| @Test |
| public void updatedCommitMessageOfNewPatchsetAutomaticallyKeepsChangeId() throws Exception { |
| Change.Id numericChangeId = changeOperations.newChange().commitMessage("Old message").create(); |
| String changeId = changeOperations.change(numericChangeId).get().changeId(); |
| |
| changeOperations.change(numericChangeId).newPatchset().commitMessage("New message").create(); |
| |
| ChangeInfo change = getChangeFromServer(numericChangeId); |
| CommitInfo currentPatchsetCommit = change.revisions.get(change.currentRevision).commit; |
| assertThat(currentPatchsetCommit).message().contains("Change-Id: " + changeId); |
| } |
| |
| @Test |
| public void newPatchsetCanHaveDifferentChangeIdFooter() throws Exception { |
| Change.Id numericChangeId = |
| changeOperations |
| .newChange() |
| .commitMessage("Old message\n\nChange-Id: I1111111111111111111111111111111111111111") |
| .create(); |
| |
| // Specifying another change-id is not an officially supported behavior of Gerrit but we might |
| // need this for some test scenarios and hence we support it in the test API. |
| changeOperations |
| .change(numericChangeId) |
| .newPatchset() |
| .commitMessage("New message\n\nChange-Id: I0123456789012345678901234567890123456789") |
| .create(); |
| |
| ChangeInfo change = getChangeFromServer(numericChangeId); |
| CommitInfo currentPatchsetCommit = change.revisions.get(change.currentRevision).commit; |
| assertThat(currentPatchsetCommit) |
| .message() |
| .contains("Change-Id: I0123456789012345678901234567890123456789"); |
| assertThat(currentPatchsetCommit) |
| .message() |
| .doesNotContain("Change-Id: I1111111111111111111111111111111111111111"); |
| // Actual change-id should not have been updated. |
| String changeId = changeOperations.change(numericChangeId).get().changeId(); |
| assertThat(changeId).isEqualTo("I1111111111111111111111111111111111111111"); |
| } |
| |
| @Test |
| public void newPatchsetCanHaveReplacedFileContent() throws Exception { |
| Change.Id changeId = changeOperations.newChange().file("file1").content("Line 1").create(); |
| |
| PatchSet.Id patchsetId = |
| changeOperations |
| .change(changeId) |
| .newPatchset() |
| .file("file1") |
| .content("Different content") |
| .create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| Map<String, FileInfo> files = change.revisions.get(change.currentRevision).files; |
| assertThatMap(files).keys().containsExactly("file1"); |
| BinaryResult fileContent = getFileContent(changeId, patchsetId, "file1"); |
| assertThat(fileContent).asString().isEqualTo("Different content"); |
| } |
| |
| @Test |
| public void newPatchsetCanHaveAdditionalFile() throws Exception { |
| Change.Id changeId = changeOperations.newChange().file("file1").content("Line 1").create(); |
| |
| PatchSet.Id patchsetId = |
| changeOperations |
| .change(changeId) |
| .newPatchset() |
| .file("file2") |
| .content("My file content") |
| .create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| Map<String, FileInfo> files = change.revisions.get(change.currentRevision).files; |
| assertThatMap(files).keys().containsExactly("file1", "file2"); |
| BinaryResult fileContent = getFileContent(changeId, patchsetId, "file2"); |
| assertThat(fileContent).asString().isEqualTo("My file content"); |
| } |
| |
| @Test |
| public void newPatchsetCanHaveLessFiles() throws Exception { |
| Change.Id changeId = |
| changeOperations |
| .newChange() |
| .file("file1") |
| .content("Line 1") |
| .file("file2") |
| .content("Line one") |
| .create(); |
| |
| changeOperations.change(changeId).newPatchset().file("file2").delete().create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| Map<String, FileInfo> files = change.revisions.get(change.currentRevision).files; |
| assertThatMap(files).keys().containsExactly("file1"); |
| } |
| |
| @Test |
| public void newPatchsetCanHaveRenamedFile() throws Exception { |
| Change.Id changeId = |
| changeOperations |
| .newChange() |
| .file("file1") |
| .content("Line 1") |
| .file("file2") |
| .content("Line one") |
| .create(); |
| |
| PatchSet.Id patchsetId = |
| changeOperations |
| .change(changeId) |
| .newPatchset() |
| .file("file2") |
| .renameTo("renamed file") |
| .create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| Map<String, FileInfo> files = change.revisions.get(change.currentRevision).files; |
| assertThatMap(files).keys().containsExactly("file1", "renamed file"); |
| BinaryResult fileContent = getFileContent(changeId, patchsetId, "renamed file"); |
| assertThat(fileContent).asString().isEqualTo("Line one"); |
| } |
| |
| @Test |
| public void newPatchsetCanHaveRenamedFileWithModifiedContent() throws Exception { |
| // We need sufficient content so that the slightly modified content is considered similar enough |
| // (> 60% line similarity) for a rename. |
| Change.Id changeId = |
| changeOperations |
| .newChange() |
| .file("file1") |
| .content("Some content") |
| .file("file2") |
| .content("Line 1\nLine 2\nLine 3\n") |
| .create(); |
| PatchSet.Id patchset1Id = |
| changeOperations.change(changeId).currentPatchset().get().patchsetId(); |
| |
| PatchSet.Id patchset2Id = |
| changeOperations |
| .change(changeId) |
| .newPatchset() |
| .file("file2") |
| .delete() |
| .file("renamed file") |
| .content("Line 1\nLine two\nLine 3\n") |
| .create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| Map<String, FileInfo> files = change.revisions.get(change.currentRevision).files; |
| assertThatMap(files).keys().containsExactly("file1", "renamed file"); |
| BinaryResult fileContent = getFileContent(changeId, patchset2Id, "renamed file"); |
| assertThat(fileContent).asString().isEqualTo("Line 1\nLine two\nLine 3\n"); |
| DiffInfo diff = |
| gApi.changes() |
| .id(changeId.get()) |
| .revision(patchset2Id.get()) |
| .file("renamed file") |
| .diffRequest() |
| .withBase(patchset1Id.getId()) |
| .get(); |
| assertThat(diff).changeType().isEqualTo(ChangeType.RENAMED); |
| } |
| |
| @Test |
| public void newPatchsetCanHaveCopiedFile() throws Exception { |
| Change.Id changeId = |
| changeOperations |
| .newChange() |
| .file("file1") |
| .content("Some content") |
| .file("file2") |
| .content("Line 1") |
| .create(); |
| PatchSet.Id patchset1Id = |
| changeOperations.change(changeId).currentPatchset().get().patchsetId(); |
| |
| // Copies currently can only happen if a rename happens at the same time. |
| PatchSet.Id patchset2Id = |
| changeOperations |
| .change(changeId) |
| .newPatchset() |
| .file("file2") |
| .renameTo("renamed/copied file 1") |
| .file("renamed/copied file 2") |
| .content("Line 1") |
| .create(); |
| |
| // We can't control which of the files Gerrit/Git considers as rename and which as copy. |
| // -> Check both for the copy. |
| DiffInfo diff1 = |
| gApi.changes() |
| .id(changeId.get()) |
| .revision(patchset2Id.get()) |
| .file("renamed/copied file 1") |
| .diffRequest() |
| .withBase(patchset1Id.getId()) |
| .get(); |
| DiffInfo diff2 = |
| gApi.changes() |
| .id(changeId.get()) |
| .revision(patchset2Id.get()) |
| .file("renamed/copied file 2") |
| .diffRequest() |
| .withBase(patchset1Id.getId()) |
| .get(); |
| assertThat(ImmutableSet.of(diff1.changeType, diff2.changeType)).contains(ChangeType.COPIED); |
| } |
| |
| @Test |
| public void newPatchsetCanHaveCopiedFileWithModifiedContent() throws Exception { |
| Change.Id changeId = |
| changeOperations |
| .newChange() |
| .file("file1") |
| .content("Some content") |
| .file("file2") |
| .content("Line 1\nLine 2\nLine 3\nLine 4\n") |
| .create(); |
| PatchSet.Id patchset1Id = |
| changeOperations.change(changeId).currentPatchset().get().patchsetId(); |
| |
| // A copy with modified content currently can only happen if the renamed file also has slightly |
| // modified content. Modify the copy slightly more as Gerrit/Git will then select it as the |
| // copied and not renamed file. |
| PatchSet.Id patchset2Id = |
| changeOperations |
| .change(changeId) |
| .newPatchset() |
| .file("file2") |
| .delete() |
| .file("renamed file") |
| .content("Line 1\nLine 1.1\nLine 2\nLine 3\nLine 4\n") |
| .file("copied file") |
| .content("Line 1\nLine 1.1\nLine 1.2\nLine 2\nLine 3\nLine 4\n") |
| .create(); |
| |
| DiffInfo diff = |
| gApi.changes() |
| .id(changeId.get()) |
| .revision(patchset2Id.get()) |
| .file("copied file") |
| .diffRequest() |
| .withBase(patchset1Id.getId()) |
| .get(); |
| assertThat(diff).changeType().isEqualTo(ChangeType.COPIED); |
| BinaryResult fileContent = getFileContent(changeId, patchset2Id, "copied file"); |
| assertThat(fileContent) |
| .asString() |
| .isEqualTo("Line 1\nLine 1.1\nLine 1.2\nLine 2\nLine 3\nLine 4\n"); |
| } |
| |
| @Test |
| public void newPatchsetCanHaveADifferentParent() throws Exception { |
| Change.Id originalParentChange = changeOperations.newChange().create(); |
| Change.Id changeId = |
| changeOperations.newChange().childOf().change(originalParentChange).create(); |
| Change.Id newParentChange = changeOperations.newChange().create(); |
| |
| changeOperations.change(changeId).newPatchset().parent().change(newParentChange).create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| CommitInfo currentPatchsetCommit = change.revisions.get(change.currentRevision).commit; |
| ObjectId newParentCommitId = |
| changeOperations.change(newParentChange).currentPatchset().get().commitId(); |
| assertThat(currentPatchsetCommit) |
| .parents() |
| .onlyElement() |
| .commit() |
| .isEqualTo(newParentCommitId.name()); |
| } |
| |
| @Test |
| public void newPatchsetCanHaveDifferentParents() throws Exception { |
| Change.Id originalParent1Change = changeOperations.newChange().create(); |
| Change.Id originalParent2Change = changeOperations.newChange().create(); |
| Change.Id changeId = |
| changeOperations |
| .newChange() |
| .mergeOf() |
| .change(originalParent1Change) |
| .and() |
| .change(originalParent2Change) |
| .create(); |
| Change.Id newParent1Change = changeOperations.newChange().create(); |
| Change.Id newParent2Change = changeOperations.newChange().create(); |
| |
| changeOperations |
| .change(changeId) |
| .newPatchset() |
| .parents() |
| .change(newParent1Change) |
| .and() |
| .change(newParent2Change) |
| .create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| CommitInfo currentPatchsetCommit = change.revisions.get(change.currentRevision).commit; |
| ObjectId newParent1CommitId = |
| changeOperations.change(newParent1Change).currentPatchset().get().commitId(); |
| ObjectId newParent2CommitId = |
| changeOperations.change(newParent2Change).currentPatchset().get().commitId(); |
| assertThat(currentPatchsetCommit) |
| .parents() |
| .comparingElementsUsing(hasSha1()) |
| .containsExactly(newParent1CommitId.name(), newParent2CommitId.name()); |
| } |
| |
| @Test |
| public void newPatchsetCanHaveADifferentNumberOfParents() throws Exception { |
| Change.Id originalParentChange = changeOperations.newChange().create(); |
| Change.Id changeId = |
| changeOperations.newChange().childOf().change(originalParentChange).create(); |
| Change.Id newParent1Change = changeOperations.newChange().create(); |
| Change.Id newParent2Change = changeOperations.newChange().create(); |
| |
| changeOperations |
| .change(changeId) |
| .newPatchset() |
| .parents() |
| .change(newParent1Change) |
| .and() |
| .change(newParent2Change) |
| .create(); |
| |
| ChangeInfo change = getChangeFromServer(changeId); |
| CommitInfo currentPatchsetCommit = change.revisions.get(change.currentRevision).commit; |
| ObjectId newParent1CommitId = |
| changeOperations.change(newParent1Change).currentPatchset().get().commitId(); |
| ObjectId newParent2CommitId = |
| changeOperations.change(newParent2Change).currentPatchset().get().commitId(); |
| assertThat(currentPatchsetCommit) |
| .parents() |
| .comparingElementsUsing(hasSha1()) |
| .containsExactly(newParent1CommitId.name(), newParent2CommitId.name()); |
| } |
| |
| @Test |
| public void newPatchsetKeepsFileContentsWithDifferentParent() throws Exception { |
| Change.Id changeId = |
| changeOperations.newChange().file("file1").content("Actual change content").create(); |
| Change.Id newParentChange = |
| changeOperations.newChange().file("file1").content("Parent content").create(); |
| |
| changeOperations.change(changeId).newPatchset().parent().change(newParentChange).create(); |
| |
| PatchSet.Id patchsetId = changeOperations.change(changeId).currentPatchset().get().patchsetId(); |
| BinaryResult file1Content = getFileContent(changeId, patchsetId, "file1"); |
| assertThat(file1Content).asString().isEqualTo("Actual change content"); |
| } |
| |
| @Test |
| public void publishedCommentCanBeRetrieved() { |
| Change.Id changeId = changeOperations.newChange().create(); |
| String commentUuid = changeOperations.change(changeId).currentPatchset().newComment().create(); |
| |
| TestHumanComment comment = changeOperations.change(changeId).comment(commentUuid).get(); |
| |
| assertThat(comment.uuid()).isEqualTo(commentUuid); |
| } |
| |
| @Test |
| public void retrievingDraftCommentAsPublishedCommentFails() { |
| Change.Id changeId = changeOperations.newChange().create(); |
| String commentUuid = |
| changeOperations.change(changeId).currentPatchset().newDraftComment().create(); |
| |
| assertThrows( |
| Exception.class, () -> changeOperations.change(changeId).comment(commentUuid).get()); |
| } |
| |
| @Test |
| public void parentUuidOfPublishedCommentCanBeRetrieved() { |
| Change.Id changeId = changeOperations.newChange().create(); |
| String parentCommentUuid = |
| changeOperations.change(changeId).currentPatchset().newComment().create(); |
| String childCommentUuid = |
| changeOperations |
| .change(changeId) |
| .currentPatchset() |
| .newComment() |
| .parentUuid(parentCommentUuid) |
| .create(); |
| |
| TestHumanComment comment = changeOperations.change(changeId).comment(childCommentUuid).get(); |
| |
| OptionalSubject.assertThat(comment.parentUuid()).value().isEqualTo(parentCommentUuid); |
| } |
| |
| @Test |
| public void tagOfPublishedCommentCanBeRetrieved() { |
| Change.Id changeId = changeOperations.newChange().create(); |
| String childCommentUuid = |
| changeOperations.change(changeId).currentPatchset().newComment().tag("tag").create(); |
| |
| TestHumanComment comment = changeOperations.change(changeId).comment(childCommentUuid).get(); |
| |
| OptionalSubject.assertThat(comment.tag()).value().isEqualTo("tag"); |
| } |
| |
| @Test |
| public void unresolvedOfUnresolvedPublishedCommentCanBeRetrieved() { |
| Change.Id changeId = changeOperations.newChange().create(); |
| String childCommentUuid = |
| changeOperations.change(changeId).currentPatchset().newComment().unresolved().create(); |
| |
| TestHumanComment comment = changeOperations.change(changeId).comment(childCommentUuid).get(); |
| |
| assertThat(comment.unresolved()).isTrue(); |
| } |
| |
| @Test |
| public void unresolvedOfResolvedPublishedCommentCanBeRetrieved() { |
| Change.Id changeId = changeOperations.newChange().create(); |
| String childCommentUuid = |
| changeOperations.change(changeId).currentPatchset().newComment().resolved().create(); |
| |
| TestHumanComment comment = changeOperations.change(changeId).comment(childCommentUuid).get(); |
| |
| assertThat(comment.unresolved()).isFalse(); |
| } |
| |
| @Test |
| public void draftCommentCanBeRetrieved() { |
| Change.Id changeId = changeOperations.newChange().create(); |
| String commentUuid = changeOperations.change(changeId).currentPatchset().newComment().create(); |
| |
| TestHumanComment comment = changeOperations.change(changeId).comment(commentUuid).get(); |
| |
| assertThat(comment.uuid()).isEqualTo(commentUuid); |
| } |
| |
| @Test |
| public void retrievingPublishedCommentAsDraftCommentFails() { |
| Change.Id changeId = changeOperations.newChange().create(); |
| String commentUuid = changeOperations.change(changeId).currentPatchset().newComment().create(); |
| |
| assertThrows( |
| Exception.class, () -> changeOperations.change(changeId).draftComment(commentUuid).get()); |
| } |
| |
| @Test |
| public void parentUuidOfDraftCommentCanBeRetrieved() { |
| Change.Id changeId = changeOperations.newChange().create(); |
| String parentCommentUuid = |
| changeOperations.change(changeId).currentPatchset().newComment().create(); |
| String childCommentUuid = |
| changeOperations |
| .change(changeId) |
| .currentPatchset() |
| .newDraftComment() |
| .parentUuid(parentCommentUuid) |
| .create(); |
| |
| TestHumanComment comment = |
| changeOperations.change(changeId).draftComment(childCommentUuid).get(); |
| |
| OptionalSubject.assertThat(comment.parentUuid()).value().isEqualTo(parentCommentUuid); |
| } |
| |
| @Test |
| public void robotCommentCanBeRetrieved() { |
| Change.Id changeId = changeOperations.newChange().create(); |
| String commentUuid = |
| changeOperations.change(changeId).currentPatchset().newRobotComment().create(); |
| |
| TestRobotComment comment = changeOperations.change(changeId).robotComment(commentUuid).get(); |
| |
| assertThat(comment.uuid()).isEqualTo(commentUuid); |
| } |
| |
| @Test |
| public void parentUuidOfRobotCommentCanBeRetrieved() { |
| Change.Id changeId = changeOperations.newChange().create(); |
| String parentCommentUuid = |
| changeOperations.change(changeId).currentPatchset().newRobotComment().create(); |
| String childCommentUuid = |
| changeOperations |
| .change(changeId) |
| .currentPatchset() |
| .newRobotComment() |
| .parentUuid(parentCommentUuid) |
| .create(); |
| |
| TestRobotComment comment = |
| changeOperations.change(changeId).robotComment(childCommentUuid).get(); |
| |
| OptionalSubject.assertThat(comment.parentUuid()).value().isEqualTo(parentCommentUuid); |
| } |
| |
| private ChangeInfo getChangeFromServer(Change.Id changeId) throws RestApiException { |
| return gApi.changes().id(changeId.get()).get(); |
| } |
| |
| private RevisionInfo getRevision(ChangeInfo change, PatchSet.Id patchsetId) { |
| return change.revisions.values().stream() |
| .filter(revision -> revision._number == patchsetId.get()) |
| .findAny() |
| .orElseThrow( |
| () -> |
| new IllegalStateException( |
| String.format( |
| "Change %d doesn't have specified patchset %d.", |
| change._number, patchsetId.get()))); |
| } |
| |
| private BinaryResult getFileContent(Change.Id changeId, PatchSet.Id patchsetId, String filePath) |
| throws RestApiException { |
| return gApi.changes().id(changeId.get()).revision(patchsetId.get()).file(filePath).content(); |
| } |
| |
| private ImmutableList<String> getGroups(Project.NameKey projectName, Change.Id changeId) { |
| return changeDataFactory.create(projectName, changeId).currentPatchSet().groups(); |
| } |
| |
| private ImmutableList<String> getGroups(Project.NameKey projectName, PatchSet.Id patchSetId) { |
| return changeDataFactory |
| .create(projectName, patchSetId.changeId()) |
| .patchSet(patchSetId) |
| .groups(); |
| } |
| |
| private Correspondence<CommitInfo, String> hasSha1() { |
| return NullAwareCorrespondence.transforming(commitInfo -> commitInfo.commit, "hasSha1"); |
| } |
| } |