blob: 463d623276ea9b3ad1fe4c347ebbb234a632e5a5 [file] [log] [blame]
// 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.plugins.codeowners.acceptance.api;
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allow;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allowCapability;
import static com.google.gerrit.plugins.codeowners.testing.CodeOwnerConfigSubject.assertThat;
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
import static com.google.gerrit.testing.GerritJUnit.assertThrows;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import com.google.gerrit.acceptance.TestAccount;
import com.google.gerrit.acceptance.testsuite.account.AccountOperations;
import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.entities.BranchNameKey;
import com.google.gerrit.entities.Permission;
import com.google.gerrit.entities.Project;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.plugins.codeowners.acceptance.AbstractCodeOwnersIT;
import com.google.gerrit.plugins.codeowners.api.RenameEmailInput;
import com.google.gerrit.plugins.codeowners.api.RenameEmailResultInfo;
import com.google.gerrit.plugins.codeowners.backend.CodeOwnerConfig;
import com.google.gerrit.plugins.codeowners.backend.CodeOwnerConfigFileUpdateScanner;
import com.google.gerrit.plugins.codeowners.restapi.RenameEmail;
import com.google.inject.Inject;
import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
/**
* Acceptance test for the {@link com.google.gerrit.plugins.codeowners.restapi.RenameEmail} REST
* endpoint.
*
* <p>Further tests for the {@link com.google.gerrit.plugins.codeowners.restapi.RenameEmail} REST
* endpoint that require using the REST API are implemented in {@link
* com.google.gerrit.plugins.codeowners.acceptance.restapi.RenameEmailRestIT}.
*/
public class RenameEmailIT extends AbstractCodeOwnersIT {
@Inject private AccountOperations accountOperations;
@Inject private ProjectOperations projectOperations;
@Inject private RequestScopeOperations requestScopeOperations;
private CodeOwnerConfigFileUpdateScanner codeOwnerConfigFileUpdateScanner;
@Before
public void setup() throws Exception {
codeOwnerConfigFileUpdateScanner =
plugin.getSysInjector().getInstance(CodeOwnerConfigFileUpdateScanner.class);
}
@Test
public void oldEmailIsRequired() throws Exception {
RenameEmailInput input = new RenameEmailInput();
input.newEmail = "new@example.com";
BadRequestException exception =
assertThrows(BadRequestException.class, () -> renameEmail(project, "master", input));
assertThat(exception).hasMessageThat().isEqualTo("old email is required");
}
@Test
public void newEmailIsRequired() throws Exception {
RenameEmailInput input = new RenameEmailInput();
input.oldEmail = "old@example.com";
BadRequestException exception =
assertThrows(BadRequestException.class, () -> renameEmail(project, "master", input));
assertThat(exception).hasMessageThat().isEqualTo("new email is required");
}
@Test
public void oldEmailNotResolvable() throws Exception {
RenameEmailInput input = new RenameEmailInput();
input.oldEmail = "unknown@example.com";
input.newEmail = admin.email();
UnprocessableEntityException exception =
assertThrows(
UnprocessableEntityException.class, () -> renameEmail(project, "master", input));
assertThat(exception)
.hasMessageThat()
.isEqualTo(String.format("cannot resolve email %s", input.oldEmail));
}
@Test
public void newEmailNotResolvable() throws Exception {
RenameEmailInput input = new RenameEmailInput();
input.oldEmail = admin.email();
input.newEmail = "unknown@example.com";
UnprocessableEntityException exception =
assertThrows(
UnprocessableEntityException.class, () -> renameEmail(project, "master", input));
assertThat(exception)
.hasMessageThat()
.isEqualTo(String.format("cannot resolve email %s", input.newEmail));
}
@Test
public void emailsMustBelongToSameAccount() throws Exception {
RenameEmailInput input = new RenameEmailInput();
input.oldEmail = admin.email();
input.newEmail = user.email();
BadRequestException exception =
assertThrows(BadRequestException.class, () -> renameEmail(project, "master", input));
assertThat(exception)
.hasMessageThat()
.isEqualTo(
String.format(
"emails must belong to the same account"
+ " (old email %s is owned by account %d, new email %s is owned by account %d)",
admin.email(), admin.id().get(), user.email(), user.id().get()));
}
@Test
public void oldAndNewEmailMustDiffer() throws Exception {
RenameEmailInput input = new RenameEmailInput();
input.oldEmail = admin.email();
input.newEmail = admin.email();
BadRequestException exception =
assertThrows(BadRequestException.class, () -> renameEmail(project, "master", input));
assertThat(exception).hasMessageThat().isEqualTo("old and new email must differ");
}
@Test
public void requiresAuthenticatedUser() throws Exception {
requestScopeOperations.setApiUserAnonymous();
AuthException authException =
assertThrows(
AuthException.class, () -> renameEmail(project, "master", new RenameEmailInput()));
assertThat(authException).hasMessageThat().contains("Authentication required");
}
@Test
public void renameEmailRequiresDirectPushPermissionsForNonProjectOwner() throws Exception {
String secondaryEmail = "user-foo@example.com";
accountOperations.account(user.id()).forUpdate().addSecondaryEmail(secondaryEmail).update();
requestScopeOperations.setApiUser(user.id());
RenameEmailInput input = new RenameEmailInput();
input.oldEmail = user.email();
input.newEmail = secondaryEmail;
AuthException exception =
assertThrows(AuthException.class, () -> renameEmail(project, "master", input));
assertThat(exception).hasMessageThat().isEqualTo("not permitted: update on refs/heads/master");
}
@Test
public void renameEmail_noCodeOwnerConfig() throws Exception {
String secondaryEmail = "user-foo@example.com";
accountOperations.account(user.id()).forUpdate().addSecondaryEmail(secondaryEmail).update();
RenameEmailInput input = new RenameEmailInput();
input.oldEmail = user.email();
input.newEmail = secondaryEmail;
RenameEmailResultInfo result = renameEmail(project, "master", input);
assertThat(result.commit).isNull();
}
@Test
public void renameEmail_noUpdateIfEmailIsNotContainedInCodeOwnerConfigs() throws Exception {
skipTestIfRenameEmailNotSupportedByCodeOwnersBackend();
codeOwnerConfigOperations
.newCodeOwnerConfig()
.project(project)
.branch("master")
.folderPath("/")
.addCodeOwnerEmail(admin.email())
.create();
codeOwnerConfigOperations
.newCodeOwnerConfig()
.project(project)
.branch("master")
.folderPath("/foo/")
.addCodeOwnerEmail(admin.email())
.create();
String secondaryEmail = "user-foo@example.com";
accountOperations.account(user.id()).forUpdate().addSecondaryEmail(secondaryEmail).update();
RenameEmailInput input = new RenameEmailInput();
input.oldEmail = user.email();
input.newEmail = secondaryEmail;
RenameEmailResultInfo result = renameEmail(project, "master", input);
assertThat(result.commit).isNull();
}
@Test
public void renameOwnEmailWithDirectPushPermission() throws Exception {
skipTestIfRenameEmailNotSupportedByCodeOwnersBackend();
CodeOwnerConfig.Key codeOwnerConfigKey1 =
codeOwnerConfigOperations
.newCodeOwnerConfig()
.project(project)
.branch("master")
.folderPath("/")
.addCodeOwnerEmail(admin.email())
.addCodeOwnerEmail(user.email())
.create();
CodeOwnerConfig.Key codeOwnerConfigKey2 =
codeOwnerConfigOperations
.newCodeOwnerConfig()
.project(project)
.branch("master")
.folderPath("/foo/")
.addCodeOwnerEmail(user.email())
.create();
// grant all users direct push permissions
projectOperations
.project(project)
.forUpdate()
.add(allow(Permission.PUSH).ref("refs/*").group(REGISTERED_USERS))
.update();
String secondaryEmail = "user-foo@example.com";
accountOperations.account(user.id()).forUpdate().addSecondaryEmail(secondaryEmail).update();
requestScopeOperations.setApiUser(user.id());
RenameEmailInput input = new RenameEmailInput();
input.oldEmail = user.email();
input.newEmail = secondaryEmail;
RenameEmailResultInfo result = renameEmail(project, "master", input);
assertThat(result.commit).isNotNull();
assertThat(codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey1).get())
.hasCodeOwnerSetsThat()
.onlyElement()
.hasCodeOwnersEmailsThat()
.containsExactly(secondaryEmail, admin.email());
assertThat(codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey2).get())
.hasCodeOwnerSetsThat()
.onlyElement()
.hasCodeOwnersEmailsThat()
.containsExactly(secondaryEmail);
}
@Test
public void renameOtherEmailWithDirectPushPermission() throws Exception {
skipTestIfRenameEmailNotSupportedByCodeOwnersBackend();
CodeOwnerConfig.Key codeOwnerConfigKey1 =
codeOwnerConfigOperations
.newCodeOwnerConfig()
.project(project)
.branch("master")
.folderPath("/")
.addCodeOwnerEmail(admin.email())
.addCodeOwnerEmail(user.email())
.create();
CodeOwnerConfig.Key codeOwnerConfigKey2 =
codeOwnerConfigOperations
.newCodeOwnerConfig()
.project(project)
.branch("master")
.folderPath("/foo/")
.addCodeOwnerEmail(admin.email())
.create();
// grant all users direct push permissions
projectOperations
.project(project)
.forUpdate()
.add(allow(Permission.PUSH).ref("refs/*").group(REGISTERED_USERS))
.update();
// Allow all users to see secondary emails.
projectOperations
.project(allProjects)
.forUpdate()
.add(allowCapability(GlobalCapability.MODIFY_ACCOUNT).group(REGISTERED_USERS))
.update();
String secondaryEmail = "admin-foo@example.com";
accountOperations.account(admin.id()).forUpdate().addSecondaryEmail(secondaryEmail).update();
requestScopeOperations.setApiUser(user.id());
RenameEmailInput input = new RenameEmailInput();
input.oldEmail = admin.email();
input.newEmail = secondaryEmail;
RenameEmailResultInfo result = renameEmail(project, "master", input);
assertThat(result.commit).isNotNull();
assertThat(codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey1).get())
.hasCodeOwnerSetsThat()
.onlyElement()
.hasCodeOwnersEmailsThat()
.containsExactly(secondaryEmail, user.email());
assertThat(codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey2).get())
.hasCodeOwnerSetsThat()
.onlyElement()
.hasCodeOwnersEmailsThat()
.containsExactly(secondaryEmail);
}
@Test
public void renameOwnEmailAsProjectOwner() throws Exception {
skipTestIfRenameEmailNotSupportedByCodeOwnersBackend();
CodeOwnerConfig.Key codeOwnerConfigKey1 =
codeOwnerConfigOperations
.newCodeOwnerConfig()
.project(project)
.branch("master")
.folderPath("/")
.addCodeOwnerEmail(user.email())
.addCodeOwnerEmail(admin.email())
.create();
CodeOwnerConfig.Key codeOwnerConfigKey2 =
codeOwnerConfigOperations
.newCodeOwnerConfig()
.project(project)
.branch("master")
.folderPath("/foo/")
.addCodeOwnerEmail(admin.email())
.create();
String secondaryEmail = "admin-foo@example.com";
accountOperations.account(admin.id()).forUpdate().addSecondaryEmail(secondaryEmail).update();
RenameEmailInput input = new RenameEmailInput();
input.oldEmail = admin.email();
input.newEmail = secondaryEmail;
RenameEmailResultInfo result = renameEmail(project, "master", input);
assertThat(result.commit).isNotNull();
assertThat(codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey1).get())
.hasCodeOwnerSetsThat()
.onlyElement()
.hasCodeOwnersEmailsThat()
.containsExactly(secondaryEmail, user.email());
assertThat(codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey2).get())
.hasCodeOwnerSetsThat()
.onlyElement()
.hasCodeOwnersEmailsThat()
.containsExactly(secondaryEmail);
}
@Test
public void renameOtherEmailAsProjectOwner() throws Exception {
skipTestIfRenameEmailNotSupportedByCodeOwnersBackend();
CodeOwnerConfig.Key codeOwnerConfigKey1 =
codeOwnerConfigOperations
.newCodeOwnerConfig()
.project(project)
.branch("master")
.folderPath("/")
.addCodeOwnerEmail(user.email())
.addCodeOwnerEmail(admin.email())
.create();
CodeOwnerConfig.Key codeOwnerConfigKey2 =
codeOwnerConfigOperations
.newCodeOwnerConfig()
.project(project)
.branch("master")
.folderPath("/foo/")
.addCodeOwnerEmail(user.email())
.create();
String secondaryEmail = "user-foo@example.com";
accountOperations.account(user.id()).forUpdate().addSecondaryEmail(secondaryEmail).update();
RenameEmailInput input = new RenameEmailInput();
input.oldEmail = user.email();
input.newEmail = secondaryEmail;
RenameEmailResultInfo result = renameEmail(project, "master", input);
assertThat(result.commit).isNotNull();
assertThat(codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey1).get())
.hasCodeOwnerSetsThat()
.onlyElement()
.hasCodeOwnersEmailsThat()
.containsExactly(secondaryEmail, admin.email());
assertThat(codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey2).get())
.hasCodeOwnerSetsThat()
.onlyElement()
.hasCodeOwnersEmailsThat()
.containsExactly(secondaryEmail);
}
@Test
public void renameEmail_callingUserBecomesCommitAuthor() throws Exception {
skipTestIfRenameEmailNotSupportedByCodeOwnersBackend();
codeOwnerConfigOperations
.newCodeOwnerConfig()
.project(project)
.branch("master")
.folderPath("/")
.addCodeOwnerEmail(user.email())
.addCodeOwnerEmail(admin.email())
.create();
String secondaryEmail = "user-foo@example.com";
accountOperations.account(user.id()).forUpdate().addSecondaryEmail(secondaryEmail).update();
RenameEmailInput input = new RenameEmailInput();
input.oldEmail = user.email();
input.newEmail = secondaryEmail;
RenameEmailResultInfo result = renameEmail(project, "master", input);
assertThat(result.commit).isNotNull();
assertThat(result.commit.author.email).isEqualTo(admin.email());
}
@Test
public void renameEmailWithDefaultCommitMessage() throws Exception {
skipTestIfRenameEmailNotSupportedByCodeOwnersBackend();
codeOwnerConfigOperations
.newCodeOwnerConfig()
.project(project)
.branch("master")
.folderPath("/")
.addCodeOwnerEmail(user.email())
.addCodeOwnerEmail(admin.email())
.create();
String secondaryEmail = "user-foo@example.com";
accountOperations.account(user.id()).forUpdate().addSecondaryEmail(secondaryEmail).update();
RenameEmailInput input = new RenameEmailInput();
input.oldEmail = user.email();
input.newEmail = secondaryEmail;
RenameEmailResultInfo result = renameEmail(project, "master", input);
assertThat(result.commit).isNotNull();
assertThat(result.commit.message).isEqualTo(RenameEmail.DEFAULT_COMMIT_MESSAGE);
}
@Test
public void renameEmailWithSpecifiedCommitMessage() throws Exception {
skipTestIfRenameEmailNotSupportedByCodeOwnersBackend();
codeOwnerConfigOperations
.newCodeOwnerConfig()
.project(project)
.branch("master")
.folderPath("/")
.addCodeOwnerEmail(user.email())
.addCodeOwnerEmail(admin.email())
.create();
String secondaryEmail = "user-foo@example.com";
accountOperations.account(user.id()).forUpdate().addSecondaryEmail(secondaryEmail).update();
RenameEmailInput input = new RenameEmailInput();
input.oldEmail = user.email();
input.newEmail = secondaryEmail;
input.message = "Update email with custom message";
RenameEmailResultInfo result = renameEmail(project, "master", input);
assertThat(result.commit).isNotNull();
assertThat(result.commit.message).isEqualTo(input.message);
}
@Test
public void renameEmail_specifiedCommitMessageIsTrimmed() throws Exception {
skipTestIfRenameEmailNotSupportedByCodeOwnersBackend();
codeOwnerConfigOperations
.newCodeOwnerConfig()
.project(project)
.branch("master")
.folderPath("/")
.addCodeOwnerEmail(user.email())
.addCodeOwnerEmail(admin.email())
.create();
String secondaryEmail = "user-foo@example.com";
accountOperations.account(user.id()).forUpdate().addSecondaryEmail(secondaryEmail).update();
String message = "Update email with custom message";
RenameEmailInput input = new RenameEmailInput();
input.oldEmail = user.email();
input.newEmail = secondaryEmail;
input.message = " " + message + "\t";
RenameEmailResultInfo result = renameEmail(project, "master", input);
assertThat(result.commit).isNotNull();
assertThat(result.commit.message).isEqualTo(message);
}
@Test
public void renameEmail_lineCommentsArePreserved() throws Exception {
skipTestIfRenameEmailNotSupportedByCodeOwnersBackend();
CodeOwnerConfig.Key codeOwnerConfigKey =
codeOwnerConfigOperations
.newCodeOwnerConfig()
.project(project)
.branch("master")
.folderPath("/")
.addCodeOwnerEmail(user.email())
.addCodeOwnerEmail(admin.email())
.create();
// insert some comments
codeOwnerConfigFileUpdateScanner.update(
BranchNameKey.create(project, "master"),
"Insert comments",
(codeOwnerConfigFilePath, codeOwnerConfigFileContent) -> {
StringBuilder b = new StringBuilder();
// insert comment line at the top of the file
b.append("# top comment\n");
Iterable<String> lines = Splitter.on('\n').split(codeOwnerConfigFileContent);
b.append(Iterables.get(lines, /* position= */ 0) + "\n");
// insert comment line in the middle of the file
b.append("# middle comment\n");
for (String line : Iterables.skip(lines, /* numberToSkip= */ 1)) {
b.append(line + "\n");
}
// insert comment line at the bottom of the file
b.append("# bottom comment\n");
return Optional.of(b.toString());
});
String secondaryEmail = "user-foo@example.com";
accountOperations.account(user.id()).forUpdate().addSecondaryEmail(secondaryEmail).update();
RenameEmailInput input = new RenameEmailInput();
input.oldEmail = user.email();
input.newEmail = secondaryEmail;
renameEmail(project, "master", input);
assertThat(codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).get())
.hasCodeOwnerSetsThat()
.onlyElement()
.hasCodeOwnersEmailsThat()
.containsExactly(secondaryEmail, admin.email());
// verify that the comments are still present
String codeOwnerConfigFileContent =
codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getContent();
Iterable<String> lines = Splitter.on('\n').split(codeOwnerConfigFileContent);
assertThat(Iterables.get(lines, /* position= */ 0)).isEqualTo("# top comment");
assertThat(Iterables.get(lines, /* position= */ 2)).isEqualTo("# middle comment");
assertThat(Iterables.get(lines, /* position= */ Iterables.size(lines) - 2))
.isEqualTo("# bottom comment");
}
@Test
public void renameEmail_inlineCommentsArePreserved() throws Exception {
skipTestIfRenameEmailNotSupportedByCodeOwnersBackend();
CodeOwnerConfig.Key codeOwnerConfigKey =
codeOwnerConfigOperations
.newCodeOwnerConfig()
.project(project)
.branch("master")
.folderPath("/")
.addCodeOwnerEmail(user.email())
.addCodeOwnerEmail(admin.email())
.create();
// insert some inline comments
codeOwnerConfigFileUpdateScanner.update(
BranchNameKey.create(project, "master"),
"Insert comments",
(codeOwnerConfigFilePath, codeOwnerConfigFileContent) -> {
StringBuilder b = new StringBuilder();
for (String line : Splitter.on('\n').split(codeOwnerConfigFileContent)) {
if (line.contains(user.email())) {
b.append(line + "# some comment\n");
continue;
}
if (line.contains(admin.email())) {
b.append(line + "# other comment\n");
continue;
}
b.append(line + "\n");
}
return Optional.of(b.toString());
});
String secondaryEmail = "user-foo@example.com";
accountOperations.account(user.id()).forUpdate().addSecondaryEmail(secondaryEmail).update();
RenameEmailInput input = new RenameEmailInput();
input.oldEmail = user.email();
input.newEmail = secondaryEmail;
renameEmail(project, "master", input);
assertThat(codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).get())
.hasCodeOwnerSetsThat()
.onlyElement()
.hasCodeOwnersEmailsThat()
.containsExactly(secondaryEmail, admin.email());
// verify that the inline comments are still present
String codeOwnerConfigFileContent =
codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getContent();
for (String line : Splitter.on('\n').split(codeOwnerConfigFileContent)) {
if (line.contains(secondaryEmail)) {
assertThat(line).endsWith("# some comment");
} else if (line.contains(admin.email())) {
assertThat(line).endsWith("# other comment");
}
}
}
@Test
public void renameEmail_emailInCommentIsReplaced() throws Exception {
skipTestIfRenameEmailNotSupportedByCodeOwnersBackend();
CodeOwnerConfig.Key codeOwnerConfigKey =
codeOwnerConfigOperations
.newCodeOwnerConfig()
.project(project)
.branch("master")
.folderPath("/")
.addCodeOwnerEmail(user.email())
.addCodeOwnerEmail(admin.email())
.create();
// insert some comments
codeOwnerConfigFileUpdateScanner.update(
BranchNameKey.create(project, "master"),
"Insert comments",
(codeOwnerConfigFilePath, codeOwnerConfigFileContent) ->
Optional.of("# foo " + user.email() + " bar\n" + codeOwnerConfigFileContent));
String secondaryEmail = "user-foo@example.com";
accountOperations.account(user.id()).forUpdate().addSecondaryEmail(secondaryEmail).update();
RenameEmailInput input = new RenameEmailInput();
input.oldEmail = user.email();
input.newEmail = secondaryEmail;
renameEmail(project, "master", input);
assertThat(codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).get())
.hasCodeOwnerSetsThat()
.onlyElement()
.hasCodeOwnersEmailsThat()
.containsExactly(secondaryEmail, admin.email());
// verify that the comments are still present
String codeOwnerConfigFileContent =
codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getContent();
assertThat(
Iterables.get(Splitter.on('\n').split(codeOwnerConfigFileContent), /* position= */ 0))
.endsWith("# foo " + secondaryEmail + " bar");
}
@Test
public void renameEmail_emailThatContainsEmailToBeReplacesAsSubstringStaysIntact()
throws Exception {
skipTestIfRenameEmailNotSupportedByCodeOwnersBackend();
TestAccount otherUser1 =
accountCreator.create(
"otherUser1", "foo" + user.email(), "Other User 1", /* displayName= */ null);
TestAccount otherUser2 =
accountCreator.create(
"otherUser2", user.email() + "bar", "Other User 2", /* displayName= */ null);
TestAccount otherUser3 =
accountCreator.create(
"otherUser3", "foo" + user.email() + "bar", "Other User 3", /* displayName= */ null);
CodeOwnerConfig.Key codeOwnerConfigKey =
codeOwnerConfigOperations
.newCodeOwnerConfig()
.project(project)
.branch("master")
.folderPath("/")
.addCodeOwnerEmail(user.email())
.addCodeOwnerEmail(otherUser1.email())
.addCodeOwnerEmail(otherUser2.email())
.addCodeOwnerEmail(otherUser3.email())
.create();
// grant all users direct push permissions
projectOperations
.project(project)
.forUpdate()
.add(allow(Permission.PUSH).ref("refs/*").group(REGISTERED_USERS))
.update();
String secondaryEmail = "user-new@example.com";
accountOperations.account(user.id()).forUpdate().addSecondaryEmail(secondaryEmail).update();
requestScopeOperations.setApiUser(user.id());
RenameEmailInput input = new RenameEmailInput();
input.oldEmail = user.email();
input.newEmail = secondaryEmail;
RenameEmailResultInfo result = renameEmail(project, "master", input);
assertThat(result.commit).isNotNull();
assertThat(codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).get())
.hasCodeOwnerSetsThat()
.onlyElement()
.hasCodeOwnersEmailsThat()
.containsExactly(
secondaryEmail, otherUser1.email(), otherUser2.email(), otherUser3.email());
}
private RenameEmailResultInfo renameEmail(
Project.NameKey projectName, String branchName, RenameEmailInput input)
throws RestApiException {
return projectCodeOwnersApiFactory
.project(projectName)
.branch(branchName)
.renameEmailInCodeOwnerConfigFiles(input);
}
private void skipTestIfRenameEmailNotSupportedByCodeOwnersBackend() {
// the proto backend doesn't support renaming emails
assumeThatCodeOwnersBackendIsNotProtoBackend();
}
}