summaryrefslogtreecommitdiffstats
path: root/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/ExternalIdIT.java
diff options
context:
space:
mode:
Diffstat (limited to 'gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/ExternalIdIT.java')
-rw-r--r--gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/ExternalIdIT.java973
1 files changed, 0 insertions, 973 deletions
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/ExternalIdIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/ExternalIdIT.java
deleted file mode 100644
index 33313d13e4..0000000000
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/account/ExternalIdIT.java
+++ /dev/null
@@ -1,973 +0,0 @@
-// Copyright (C) 2017 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.rest.account;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.GitUtil.fetch;
-import static com.google.gerrit.acceptance.GitUtil.pushHead;
-import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_MAILTO;
-import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_USERNAME;
-import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_UUID;
-import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static java.util.stream.Collectors.toList;
-import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
-import static org.junit.Assert.fail;
-
-import com.github.rholder.retry.BlockStrategy;
-import com.github.rholder.retry.Retryer;
-import com.github.rholder.retry.RetryerBuilder;
-import com.github.rholder.retry.StopStrategies;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.RestResponse;
-import com.google.gerrit.acceptance.Sandboxed;
-import com.google.gerrit.common.data.GlobalCapability;
-import com.google.gerrit.common.data.Permission;
-import com.google.gerrit.extensions.api.config.ConsistencyCheckInfo;
-import com.google.gerrit.extensions.api.config.ConsistencyCheckInfo.ConsistencyProblemInfo;
-import com.google.gerrit.extensions.api.config.ConsistencyCheckInput;
-import com.google.gerrit.extensions.api.config.ConsistencyCheckInput.CheckAccountExternalIdsInput;
-import com.google.gerrit.extensions.common.AccountExternalIdInfo;
-import com.google.gerrit.extensions.restapi.AuthException;
-import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
-import com.google.gerrit.metrics.MetricMaker;
-import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.reviewdb.client.RefNames;
-import com.google.gerrit.server.account.externalids.DisabledExternalIdCache;
-import com.google.gerrit.server.account.externalids.ExternalId;
-import com.google.gerrit.server.account.externalids.ExternalIdReader;
-import com.google.gerrit.server.account.externalids.ExternalIds;
-import com.google.gerrit.server.account.externalids.ExternalIdsUpdate;
-import com.google.gerrit.server.account.externalids.ExternalIdsUpdate.RefsMetaExternalIdsUpdate;
-import com.google.gerrit.server.config.AllUsersName;
-import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
-import com.google.gerrit.server.git.LockFailureException;
-import com.google.gson.reflect.TypeToken;
-import com.google.gwtorm.server.OrmDuplicateKeyException;
-import com.google.gwtorm.server.OrmException;
-import com.google.inject.Inject;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import org.eclipse.jgit.api.errors.TransportException;
-import org.eclipse.jgit.errors.ConfigInvalidException;
-import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
-import org.eclipse.jgit.junit.TestRepository;
-import org.eclipse.jgit.lib.Config;
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.ObjectInserter;
-import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.notes.NoteMap;
-import org.eclipse.jgit.revwalk.RevWalk;
-import org.eclipse.jgit.transport.PushResult;
-import org.eclipse.jgit.transport.RemoteRefUpdate;
-import org.eclipse.jgit.transport.RemoteRefUpdate.Status;
-import org.eclipse.jgit.util.MutableInteger;
-import org.junit.Test;
-
-@Sandboxed
-public class ExternalIdIT extends AbstractDaemonTest {
- @Inject private AllUsersName allUsers;
- @Inject private ExternalIdsUpdate.Server extIdsUpdate;
- @Inject private ExternalIds externalIds;
- @Inject private ExternalIdReader externalIdReader;
- @Inject private MetricMaker metricMaker;
-
- @Test
- public void getExternalIds() throws Exception {
- Collection<ExternalId> expectedIds = accountCache.get(user.getId()).getExternalIds();
- List<AccountExternalIdInfo> expectedIdInfos = toExternalIdInfos(expectedIds);
-
- RestResponse response = userRestSession.get("/accounts/self/external.ids");
- response.assertOK();
-
- List<AccountExternalIdInfo> results =
- newGson()
- .fromJson(
- response.getReader(), new TypeToken<List<AccountExternalIdInfo>>() {}.getType());
-
- Collections.sort(expectedIdInfos);
- Collections.sort(results);
- assertThat(results).containsExactlyElementsIn(expectedIdInfos);
- }
-
- @Test
- public void getExternalIdsOfOtherUserNotAllowed() throws Exception {
- setApiUser(user);
- exception.expect(AuthException.class);
- exception.expectMessage("access database not permitted");
- gApi.accounts().id(admin.id.get()).getExternalIds();
- }
-
- @Test
- public void getExternalIdsOfOtherUserWithAccessDatabase() throws Exception {
- allowGlobalCapabilities(REGISTERED_USERS, GlobalCapability.ACCESS_DATABASE);
-
- Collection<ExternalId> expectedIds = accountCache.get(admin.getId()).getExternalIds();
- List<AccountExternalIdInfo> expectedIdInfos = toExternalIdInfos(expectedIds);
-
- RestResponse response = userRestSession.get("/accounts/" + admin.id + "/external.ids");
- response.assertOK();
-
- List<AccountExternalIdInfo> results =
- newGson()
- .fromJson(
- response.getReader(), new TypeToken<List<AccountExternalIdInfo>>() {}.getType());
-
- Collections.sort(expectedIdInfos);
- Collections.sort(results);
- assertThat(results).containsExactlyElementsIn(expectedIdInfos);
- }
-
- @Test
- public void deleteExternalIds() throws Exception {
- setApiUser(user);
- List<AccountExternalIdInfo> externalIds = gApi.accounts().self().getExternalIds();
-
- List<String> toDelete = new ArrayList<>();
- List<AccountExternalIdInfo> expectedIds = new ArrayList<>();
- for (AccountExternalIdInfo id : externalIds) {
- if (id.canDelete != null && id.canDelete) {
- toDelete.add(id.identity);
- continue;
- }
- expectedIds.add(id);
- }
-
- assertThat(toDelete).hasSize(1);
-
- RestResponse response = userRestSession.post("/accounts/self/external.ids:delete", toDelete);
- response.assertNoContent();
- List<AccountExternalIdInfo> results = gApi.accounts().self().getExternalIds();
- // The external ID in WebSession will not be set for tests, resulting that
- // "mailto:user@example.com" can be deleted while "username:user" can't.
- assertThat(results).hasSize(1);
- assertThat(results).containsExactlyElementsIn(expectedIds);
- }
-
- @Test
- public void deleteExternalIdsOfOtherUserNotAllowed() throws Exception {
- List<AccountExternalIdInfo> extIds = gApi.accounts().self().getExternalIds();
- setApiUser(user);
- exception.expect(AuthException.class);
- exception.expectMessage("access database not permitted");
- gApi.accounts()
- .id(admin.id.get())
- .deleteExternalIds(extIds.stream().map(e -> e.identity).collect(toList()));
- }
-
- @Test
- public void deleteExternalIdOfOtherUserUnderOwnAccount_UnprocessableEntity() throws Exception {
- List<AccountExternalIdInfo> extIds = gApi.accounts().self().getExternalIds();
- setApiUser(user);
- exception.expect(UnprocessableEntityException.class);
- exception.expectMessage(String.format("External id %s does not exist", extIds.get(0).identity));
- gApi.accounts()
- .self()
- .deleteExternalIds(extIds.stream().map(e -> e.identity).collect(toList()));
- }
-
- @Test
- public void deleteExternalIdsOfOtherUserWithAccessDatabase() throws Exception {
- allowGlobalCapabilities(REGISTERED_USERS, GlobalCapability.ACCESS_DATABASE);
-
- List<AccountExternalIdInfo> externalIds = gApi.accounts().self().getExternalIds();
-
- List<String> toDelete = new ArrayList<>();
- List<AccountExternalIdInfo> expectedIds = new ArrayList<>();
- for (AccountExternalIdInfo id : externalIds) {
- if (id.canDelete != null && id.canDelete) {
- toDelete.add(id.identity);
- continue;
- }
- expectedIds.add(id);
- }
-
- assertThat(toDelete).hasSize(1);
-
- setApiUser(user);
- RestResponse response =
- userRestSession.post("/accounts/" + admin.id + "/external.ids:delete", toDelete);
- response.assertNoContent();
- List<AccountExternalIdInfo> results = gApi.accounts().id(admin.id.get()).getExternalIds();
- // The external ID in WebSession will not be set for tests, resulting that
- // "mailto:user@example.com" can be deleted while "username:user" can't.
- assertThat(results).hasSize(1);
- assertThat(results).containsExactlyElementsIn(expectedIds);
- }
-
- @Test
- public void deleteExternalIdOfPreferredEmail() throws Exception {
- String preferredEmail = gApi.accounts().self().get().email;
- assertThat(preferredEmail).isNotNull();
-
- gApi.accounts()
- .self()
- .deleteExternalIds(
- ImmutableList.of(ExternalId.Key.create(SCHEME_MAILTO, preferredEmail).get()));
- assertThat(gApi.accounts().self().get().email).isNull();
- }
-
- @Test
- public void deleteExternalIds_Conflict() throws Exception {
- List<String> toDelete = new ArrayList<>();
- String externalIdStr = "username:" + user.username;
- toDelete.add(externalIdStr);
- RestResponse response = userRestSession.post("/accounts/self/external.ids:delete", toDelete);
- response.assertConflict();
- assertThat(response.getEntityContent())
- .isEqualTo(String.format("External id %s cannot be deleted", externalIdStr));
- }
-
- @Test
- public void deleteExternalIds_UnprocessableEntity() throws Exception {
- List<String> toDelete = new ArrayList<>();
- String externalIdStr = "mailto:user@domain.com";
- toDelete.add(externalIdStr);
- RestResponse response = userRestSession.post("/accounts/self/external.ids:delete", toDelete);
- response.assertUnprocessableEntity();
- assertThat(response.getEntityContent())
- .isEqualTo(String.format("External id %s does not exist", externalIdStr));
- }
-
- @Test
- public void fetchExternalIdsBranch() throws Exception {
- TestRepository<InMemoryRepository> allUsersRepo = cloneProject(allUsers, user);
-
- // refs/meta/external-ids is only visible to users with the 'Access Database' capability
- try {
- fetch(allUsersRepo, RefNames.REFS_EXTERNAL_IDS);
- fail("expected TransportException");
- } catch (TransportException e) {
- assertThat(e.getMessage())
- .isEqualTo(
- "Remote does not have " + RefNames.REFS_EXTERNAL_IDS + " available for fetch.");
- }
-
- allowGlobalCapabilities(REGISTERED_USERS, GlobalCapability.ACCESS_DATABASE);
-
- // re-clone to get new request context, otherwise the old global capabilities are still cached
- // in the IdentifiedUser object
- allUsersRepo = cloneProject(allUsers, user);
- fetch(allUsersRepo, RefNames.REFS_EXTERNAL_IDS);
- }
-
- @Test
- public void pushToExternalIdsBranch() throws Exception {
- allowGlobalCapabilities(REGISTERED_USERS, GlobalCapability.ACCESS_DATABASE);
-
- TestRepository<InMemoryRepository> allUsersRepo = cloneProject(allUsers);
- fetch(allUsersRepo, RefNames.REFS_EXTERNAL_IDS + ":" + RefNames.REFS_EXTERNAL_IDS);
- allUsersRepo.reset(RefNames.REFS_EXTERNAL_IDS);
-
- // different case email is allowed
- ExternalId newExtId = createExternalIdWithOtherCaseEmail("foo:bar");
- addExtId(allUsersRepo, newExtId);
- allUsersRepo.reset(RefNames.REFS_EXTERNAL_IDS);
-
- List<AccountExternalIdInfo> extIdsBefore = gApi.accounts().self().getExternalIds();
-
- allowPushOfExternalIds();
- PushResult r = pushHead(allUsersRepo, RefNames.REFS_EXTERNAL_IDS);
- assertThat(r.getRemoteUpdate(RefNames.REFS_EXTERNAL_IDS).getStatus()).isEqualTo(Status.OK);
-
- List<AccountExternalIdInfo> extIdsAfter = gApi.accounts().self().getExternalIds();
- assertThat(extIdsAfter)
- .containsExactlyElementsIn(
- Iterables.concat(extIdsBefore, ImmutableSet.of(toExternalIdInfo(newExtId))));
- }
-
- @Test
- public void pushToExternalIdsBranchRejectsExternalIdWithoutAccountId() throws Exception {
- allowGlobalCapabilities(REGISTERED_USERS, GlobalCapability.ACCESS_DATABASE);
-
- TestRepository<InMemoryRepository> allUsersRepo = cloneProject(allUsers);
- fetch(allUsersRepo, RefNames.REFS_EXTERNAL_IDS + ":" + RefNames.REFS_EXTERNAL_IDS);
- allUsersRepo.reset(RefNames.REFS_EXTERNAL_IDS);
-
- insertExternalIdWithoutAccountId(
- allUsersRepo.getRepository(), allUsersRepo.getRevWalk(), "foo:bar");
- allUsersRepo.reset(RefNames.REFS_EXTERNAL_IDS);
-
- allowPushOfExternalIds();
- PushResult r = pushHead(allUsersRepo, RefNames.REFS_EXTERNAL_IDS);
- assertRefUpdateFailure(r.getRemoteUpdate(RefNames.REFS_EXTERNAL_IDS), "invalid external IDs");
- }
-
- @Test
- public void pushToExternalIdsBranchRejectsExternalIdWithKeyThatDoesntMatchTheNoteId()
- throws Exception {
- allowGlobalCapabilities(REGISTERED_USERS, GlobalCapability.ACCESS_DATABASE);
-
- TestRepository<InMemoryRepository> allUsersRepo = cloneProject(allUsers);
- fetch(allUsersRepo, RefNames.REFS_EXTERNAL_IDS + ":" + RefNames.REFS_EXTERNAL_IDS);
- allUsersRepo.reset(RefNames.REFS_EXTERNAL_IDS);
-
- insertExternalIdWithKeyThatDoesntMatchNoteId(
- allUsersRepo.getRepository(), allUsersRepo.getRevWalk(), "foo:bar");
- allUsersRepo.reset(RefNames.REFS_EXTERNAL_IDS);
-
- allowPushOfExternalIds();
- PushResult r = pushHead(allUsersRepo, RefNames.REFS_EXTERNAL_IDS);
- assertRefUpdateFailure(r.getRemoteUpdate(RefNames.REFS_EXTERNAL_IDS), "invalid external IDs");
- }
-
- @Test
- public void pushToExternalIdsBranchRejectsExternalIdWithInvalidConfig() throws Exception {
- allowGlobalCapabilities(REGISTERED_USERS, GlobalCapability.ACCESS_DATABASE);
-
- TestRepository<InMemoryRepository> allUsersRepo = cloneProject(allUsers);
- fetch(allUsersRepo, RefNames.REFS_EXTERNAL_IDS + ":" + RefNames.REFS_EXTERNAL_IDS);
- allUsersRepo.reset(RefNames.REFS_EXTERNAL_IDS);
-
- insertExternalIdWithInvalidConfig(
- allUsersRepo.getRepository(), allUsersRepo.getRevWalk(), "foo:bar");
- allUsersRepo.reset(RefNames.REFS_EXTERNAL_IDS);
-
- allowPushOfExternalIds();
- PushResult r = pushHead(allUsersRepo, RefNames.REFS_EXTERNAL_IDS);
- assertRefUpdateFailure(r.getRemoteUpdate(RefNames.REFS_EXTERNAL_IDS), "invalid external IDs");
- }
-
- @Test
- public void pushToExternalIdsBranchRejectsExternalIdWithEmptyNote() throws Exception {
- allowGlobalCapabilities(REGISTERED_USERS, GlobalCapability.ACCESS_DATABASE);
-
- TestRepository<InMemoryRepository> allUsersRepo = cloneProject(allUsers);
- fetch(allUsersRepo, RefNames.REFS_EXTERNAL_IDS + ":" + RefNames.REFS_EXTERNAL_IDS);
- allUsersRepo.reset(RefNames.REFS_EXTERNAL_IDS);
-
- insertExternalIdWithEmptyNote(
- allUsersRepo.getRepository(), allUsersRepo.getRevWalk(), "foo:bar");
- allUsersRepo.reset(RefNames.REFS_EXTERNAL_IDS);
-
- allowPushOfExternalIds();
- PushResult r = pushHead(allUsersRepo, RefNames.REFS_EXTERNAL_IDS);
- assertRefUpdateFailure(r.getRemoteUpdate(RefNames.REFS_EXTERNAL_IDS), "invalid external IDs");
- }
-
- @Test
- public void pushToExternalIdsBranchRejectsExternalIdForNonExistingAccount() throws Exception {
- testPushToExternalIdsBranchRejectsInvalidExternalId(
- createExternalIdForNonExistingAccount("foo:bar"));
- }
-
- @Test
- public void pushToExternalIdsBranchRejectsExternalIdWithInvalidEmail() throws Exception {
- testPushToExternalIdsBranchRejectsInvalidExternalId(
- createExternalIdWithInvalidEmail("foo:bar"));
- }
-
- @Test
- public void pushToExternalIdsBranchRejectsDuplicateEmails() throws Exception {
- testPushToExternalIdsBranchRejectsInvalidExternalId(
- createExternalIdWithDuplicateEmail("foo:bar"));
- }
-
- @Test
- public void pushToExternalIdsBranchRejectsBadPassword() throws Exception {
- testPushToExternalIdsBranchRejectsInvalidExternalId(createExternalIdWithBadPassword("foo"));
- }
-
- private void testPushToExternalIdsBranchRejectsInvalidExternalId(ExternalId invalidExtId)
- throws Exception {
- allowGlobalCapabilities(REGISTERED_USERS, GlobalCapability.ACCESS_DATABASE);
-
- TestRepository<InMemoryRepository> allUsersRepo = cloneProject(allUsers);
- fetch(allUsersRepo, RefNames.REFS_EXTERNAL_IDS + ":" + RefNames.REFS_EXTERNAL_IDS);
- allUsersRepo.reset(RefNames.REFS_EXTERNAL_IDS);
-
- addExtId(allUsersRepo, invalidExtId);
- allUsersRepo.reset(RefNames.REFS_EXTERNAL_IDS);
-
- allowPushOfExternalIds();
- PushResult r = pushHead(allUsersRepo, RefNames.REFS_EXTERNAL_IDS);
- assertRefUpdateFailure(r.getRemoteUpdate(RefNames.REFS_EXTERNAL_IDS), "invalid external IDs");
- }
-
- @Test
- public void readExternalIdsWhenInvalidExternalIdsExist() throws Exception {
- allowGlobalCapabilities(REGISTERED_USERS, GlobalCapability.ACCESS_DATABASE);
- resetCurrentApiUser();
-
- insertValidExternalIds();
- insertInvalidButParsableExternalIds();
-
- Set<ExternalId> parseableExtIds = externalIds.all();
-
- insertNonParsableExternalIds();
-
- Set<ExternalId> extIds = externalIds.all();
- assertThat(extIds).containsExactlyElementsIn(parseableExtIds);
-
- for (ExternalId parseableExtId : parseableExtIds) {
- ExternalId extId = externalIds.get(parseableExtId.key());
- assertThat(extId).isEqualTo(parseableExtId);
- }
- }
-
- @Test
- public void checkConsistency() throws Exception {
- allowGlobalCapabilities(REGISTERED_USERS, GlobalCapability.ACCESS_DATABASE);
- resetCurrentApiUser();
-
- insertValidExternalIds();
-
- ConsistencyCheckInput input = new ConsistencyCheckInput();
- input.checkAccountExternalIds = new CheckAccountExternalIdsInput();
- ConsistencyCheckInfo checkInfo = gApi.config().server().checkConsistency(input);
- assertThat(checkInfo.checkAccountExternalIdsResult.problems).isEmpty();
-
- Set<ConsistencyProblemInfo> expectedProblems = new HashSet<>();
- expectedProblems.addAll(insertInvalidButParsableExternalIds());
- expectedProblems.addAll(insertNonParsableExternalIds());
-
- checkInfo = gApi.config().server().checkConsistency(input);
- assertThat(checkInfo.checkAccountExternalIdsResult.problems).hasSize(expectedProblems.size());
- assertThat(checkInfo.checkAccountExternalIdsResult.problems)
- .containsExactlyElementsIn(expectedProblems);
- }
-
- @Test
- public void checkConsistencyNotAllowed() throws Exception {
- exception.expect(AuthException.class);
- exception.expectMessage("access database not permitted");
- gApi.config().server().checkConsistency(new ConsistencyCheckInput());
- }
-
- private ConsistencyProblemInfo consistencyError(String message) {
- return new ConsistencyProblemInfo(ConsistencyProblemInfo.Status.ERROR, message);
- }
-
- private void insertValidExternalIds() throws IOException, ConfigInvalidException, OrmException {
- MutableInteger i = new MutableInteger();
- String scheme = "valid";
- ExternalIdsUpdate u = extIdsUpdate.create();
-
- // create valid external IDs
- u.insert(
- ExternalId.createWithPassword(
- ExternalId.Key.parse(nextId(scheme, i)),
- admin.id,
- "admin.other@example.com",
- "secret-password"));
- u.insert(createExternalIdWithOtherCaseEmail(nextId(scheme, i)));
- }
-
- private Set<ConsistencyProblemInfo> insertInvalidButParsableExternalIds()
- throws IOException, ConfigInvalidException, OrmException {
- MutableInteger i = new MutableInteger();
- String scheme = "invalid";
- ExternalIdsUpdate u = extIdsUpdate.create();
-
- Set<ConsistencyProblemInfo> expectedProblems = new HashSet<>();
- ExternalId extIdForNonExistingAccount =
- createExternalIdForNonExistingAccount(nextId(scheme, i));
- u.insert(extIdForNonExistingAccount);
- expectedProblems.add(
- consistencyError(
- "External ID '"
- + extIdForNonExistingAccount.key().get()
- + "' belongs to account that doesn't exist: "
- + extIdForNonExistingAccount.accountId().get()));
-
- ExternalId extIdWithInvalidEmail = createExternalIdWithInvalidEmail(nextId(scheme, i));
- u.insert(extIdWithInvalidEmail);
- expectedProblems.add(
- consistencyError(
- "External ID '"
- + extIdWithInvalidEmail.key().get()
- + "' has an invalid email: "
- + extIdWithInvalidEmail.email()));
-
- ExternalId extIdWithDuplicateEmail = createExternalIdWithDuplicateEmail(nextId(scheme, i));
- u.insert(extIdWithDuplicateEmail);
- expectedProblems.add(
- consistencyError(
- "Email '"
- + extIdWithDuplicateEmail.email()
- + "' is not unique, it's used by the following external IDs: '"
- + extIdWithDuplicateEmail.key().get()
- + "', 'mailto:"
- + extIdWithDuplicateEmail.email()
- + "'"));
-
- ExternalId extIdWithBadPassword = createExternalIdWithBadPassword("admin-username");
- u.insert(extIdWithBadPassword);
- expectedProblems.add(
- consistencyError(
- "External ID '"
- + extIdWithBadPassword.key().get()
- + "' has an invalid password: unrecognized algorithm"));
-
- return expectedProblems;
- }
-
- private Set<ConsistencyProblemInfo> insertNonParsableExternalIds() throws IOException {
- MutableInteger i = new MutableInteger();
- String scheme = "corrupt";
-
- Set<ConsistencyProblemInfo> expectedProblems = new HashSet<>();
- try (Repository repo = repoManager.openRepository(allUsers);
- RevWalk rw = new RevWalk(repo)) {
- String externalId = nextId(scheme, i);
- String noteId = insertExternalIdWithoutAccountId(repo, rw, externalId);
- expectedProblems.add(
- consistencyError(
- "Invalid external ID config for note '"
- + noteId
- + "': Value for 'externalId."
- + externalId
- + ".accountId' is missing, expected account ID"));
-
- externalId = nextId(scheme, i);
- noteId = insertExternalIdWithKeyThatDoesntMatchNoteId(repo, rw, externalId);
- expectedProblems.add(
- consistencyError(
- "Invalid external ID config for note '"
- + noteId
- + "': SHA1 of external ID '"
- + externalId
- + "' does not match note ID '"
- + noteId
- + "'"));
-
- noteId = insertExternalIdWithInvalidConfig(repo, rw, nextId(scheme, i));
- expectedProblems.add(
- consistencyError(
- "Invalid external ID config for note '" + noteId + "': Invalid line in config file"));
-
- noteId = insertExternalIdWithEmptyNote(repo, rw, nextId(scheme, i));
- expectedProblems.add(
- consistencyError(
- "Invalid external ID config for note '"
- + noteId
- + "': Expected exactly 1 'externalId' section, found 0"));
- }
-
- return expectedProblems;
- }
-
- private ExternalId createExternalIdWithOtherCaseEmail(String externalId) {
- return ExternalId.createWithPassword(
- ExternalId.Key.parse(externalId), admin.id, admin.email.toUpperCase(Locale.US), "password");
- }
-
- private String insertExternalIdWithoutAccountId(Repository repo, RevWalk rw, String externalId)
- throws IOException {
- ObjectId rev = ExternalIdReader.readRevision(repo);
- NoteMap noteMap = ExternalIdReader.readNoteMap(rw, rev);
-
- ExternalId extId = ExternalId.create(ExternalId.Key.parse(externalId), admin.id);
-
- try (ObjectInserter ins = repo.newObjectInserter()) {
- ObjectId noteId = extId.key().sha1();
- Config c = new Config();
- extId.writeToConfig(c);
- c.unset("externalId", extId.key().get(), "accountId");
- byte[] raw = c.toText().getBytes(UTF_8);
- ObjectId dataBlob = ins.insert(OBJ_BLOB, raw);
- noteMap.set(noteId, dataBlob);
-
- ExternalIdsUpdate.commit(
- allUsers,
- repo,
- rw,
- ins,
- rev,
- noteMap,
- "Add external ID",
- admin.getIdent(),
- admin.getIdent(),
- null,
- GitReferenceUpdated.DISABLED);
- return noteId.getName();
- }
- }
-
- private String insertExternalIdWithKeyThatDoesntMatchNoteId(
- Repository repo, RevWalk rw, String externalId) throws IOException {
- ObjectId rev = ExternalIdReader.readRevision(repo);
- NoteMap noteMap = ExternalIdReader.readNoteMap(rw, rev);
-
- ExternalId extId = ExternalId.create(ExternalId.Key.parse(externalId), admin.id);
-
- try (ObjectInserter ins = repo.newObjectInserter()) {
- ObjectId noteId = ExternalId.Key.parse(externalId + "x").sha1();
- Config c = new Config();
- extId.writeToConfig(c);
- byte[] raw = c.toText().getBytes(UTF_8);
- ObjectId dataBlob = ins.insert(OBJ_BLOB, raw);
- noteMap.set(noteId, dataBlob);
-
- ExternalIdsUpdate.commit(
- allUsers,
- repo,
- rw,
- ins,
- rev,
- noteMap,
- "Add external ID",
- admin.getIdent(),
- admin.getIdent(),
- null,
- GitReferenceUpdated.DISABLED);
- return noteId.getName();
- }
- }
-
- private String insertExternalIdWithInvalidConfig(Repository repo, RevWalk rw, String externalId)
- throws IOException {
- ObjectId rev = ExternalIdReader.readRevision(repo);
- NoteMap noteMap = ExternalIdReader.readNoteMap(rw, rev);
-
- try (ObjectInserter ins = repo.newObjectInserter()) {
- ObjectId noteId = ExternalId.Key.parse(externalId).sha1();
- byte[] raw = "bad-config".getBytes(UTF_8);
- ObjectId dataBlob = ins.insert(OBJ_BLOB, raw);
- noteMap.set(noteId, dataBlob);
-
- ExternalIdsUpdate.commit(
- allUsers,
- repo,
- rw,
- ins,
- rev,
- noteMap,
- "Add external ID",
- admin.getIdent(),
- admin.getIdent(),
- null,
- GitReferenceUpdated.DISABLED);
- return noteId.getName();
- }
- }
-
- private String insertExternalIdWithEmptyNote(Repository repo, RevWalk rw, String externalId)
- throws IOException {
- ObjectId rev = ExternalIdReader.readRevision(repo);
- NoteMap noteMap = ExternalIdReader.readNoteMap(rw, rev);
-
- try (ObjectInserter ins = repo.newObjectInserter()) {
- ObjectId noteId = ExternalId.Key.parse(externalId).sha1();
- byte[] raw = "".getBytes(UTF_8);
- ObjectId dataBlob = ins.insert(OBJ_BLOB, raw);
- noteMap.set(noteId, dataBlob);
-
- ExternalIdsUpdate.commit(
- allUsers,
- repo,
- rw,
- ins,
- rev,
- noteMap,
- "Add external ID",
- admin.getIdent(),
- admin.getIdent(),
- null,
- GitReferenceUpdated.DISABLED);
- return noteId.getName();
- }
- }
-
- private ExternalId createExternalIdForNonExistingAccount(String externalId) {
- return ExternalId.create(ExternalId.Key.parse(externalId), new Account.Id(1));
- }
-
- private ExternalId createExternalIdWithInvalidEmail(String externalId) {
- return ExternalId.createWithEmail(ExternalId.Key.parse(externalId), admin.id, "invalid-email");
- }
-
- private ExternalId createExternalIdWithDuplicateEmail(String externalId) {
- return ExternalId.createWithEmail(ExternalId.Key.parse(externalId), admin.id, admin.email);
- }
-
- private ExternalId createExternalIdWithBadPassword(String username) {
- return ExternalId.create(
- ExternalId.Key.create(SCHEME_USERNAME, username),
- admin.id,
- null,
- "non-hashed-password-is-not-allowed");
- }
-
- private static String nextId(String scheme, MutableInteger i) {
- return scheme + ":foo" + ++i.value;
- }
-
- @Test
- public void retryOnLockFailure() throws Exception {
- Retryer<RefsMetaExternalIdsUpdate> retryer =
- ExternalIdsUpdate.retryerBuilder()
- .withBlockStrategy(
- new BlockStrategy() {
- @Override
- public void block(long sleepTime) {
- // Don't sleep in tests.
- }
- })
- .build();
-
- ExternalId.Key fooId = ExternalId.Key.create("foo", "foo");
- ExternalId.Key barId = ExternalId.Key.create("bar", "bar");
-
- final AtomicBoolean doneBgUpdate = new AtomicBoolean(false);
- ExternalIdsUpdate update =
- new ExternalIdsUpdate(
- repoManager,
- accountCache,
- allUsers,
- metricMaker,
- externalIds,
- new DisabledExternalIdCache(),
- serverIdent.get(),
- serverIdent.get(),
- null,
- GitReferenceUpdated.DISABLED,
- () -> {
- if (!doneBgUpdate.getAndSet(true)) {
- try {
- extIdsUpdate.create().insert(ExternalId.create(barId, admin.id));
- } catch (IOException | ConfigInvalidException | OrmException e) {
- // Ignore, the successful insertion of the external ID is asserted later
- }
- }
- },
- retryer);
- assertThat(doneBgUpdate.get()).isFalse();
- update.insert(ExternalId.create(fooId, admin.id));
- assertThat(doneBgUpdate.get()).isTrue();
-
- assertThat(externalIds.get(fooId)).isNotNull();
- assertThat(externalIds.get(barId)).isNotNull();
- }
-
- @Test
- public void failAfterRetryerGivesUp() throws Exception {
- ExternalId.Key[] extIdsKeys = {
- ExternalId.Key.create("foo", "foo"),
- ExternalId.Key.create("bar", "bar"),
- ExternalId.Key.create("baz", "baz")
- };
- final AtomicInteger bgCounter = new AtomicInteger(0);
- ExternalIdsUpdate update =
- new ExternalIdsUpdate(
- repoManager,
- accountCache,
- allUsers,
- metricMaker,
- externalIds,
- new DisabledExternalIdCache(),
- serverIdent.get(),
- serverIdent.get(),
- null,
- GitReferenceUpdated.DISABLED,
- () -> {
- try {
- extIdsUpdate
- .create()
- .insert(ExternalId.create(extIdsKeys[bgCounter.getAndAdd(1)], admin.id));
- } catch (IOException | ConfigInvalidException | OrmException e) {
- // Ignore, the successful insertion of the external ID is asserted later
- }
- },
- RetryerBuilder.<RefsMetaExternalIdsUpdate>newBuilder()
- .retryIfException(e -> e instanceof LockFailureException)
- .withStopStrategy(StopStrategies.stopAfterAttempt(extIdsKeys.length))
- .build());
- assertThat(bgCounter.get()).isEqualTo(0);
- try {
- update.insert(ExternalId.create(ExternalId.Key.create("abc", "abc"), admin.id));
- fail("expected LockFailureException");
- } catch (LockFailureException e) {
- // Ignore, expected
- }
- assertThat(bgCounter.get()).isEqualTo(extIdsKeys.length);
- for (ExternalId.Key extIdKey : extIdsKeys) {
- assertThat(externalIds.get(extIdKey)).isNotNull();
- }
- }
-
- @Test
- public void readExternalIdWithAccountIdThatCanBeExpressedInKiB() throws Exception {
- ExternalId.Key extIdKey = ExternalId.Key.parse("foo:bar");
- Account.Id accountId = new Account.Id(1024 * 100);
- extIdsUpdate.create().insert(ExternalId.create(extIdKey, accountId));
- ExternalId extId = externalIds.get(extIdKey);
- assertThat(extId.accountId()).isEqualTo(accountId);
- }
-
- @Test
- public void checkNoReloadAfterUpdate() throws Exception {
- Set<ExternalId> expectedExtIds = new HashSet<>(externalIds.byAccount(admin.id));
- externalIdReader.setFailOnLoad(true);
-
- // insert external ID
- ExternalId extId = ExternalId.create("foo", "bar", admin.id);
- extIdsUpdate.create().insert(extId);
- expectedExtIds.add(extId);
- assertThat(externalIds.byAccount(admin.id)).containsExactlyElementsIn(expectedExtIds);
-
- // update external ID
- expectedExtIds.remove(extId);
- extId = ExternalId.createWithEmail("foo", "bar", admin.id, "foo.bar@example.com");
- extIdsUpdate.create().upsert(extId);
- expectedExtIds.add(extId);
- assertThat(externalIds.byAccount(admin.id)).containsExactlyElementsIn(expectedExtIds);
-
- // delete external ID
- extIdsUpdate.create().delete(extId);
- expectedExtIds.remove(extId);
- assertThat(externalIds.byAccount(admin.id)).containsExactlyElementsIn(expectedExtIds);
- }
-
- @Test
- public void byAccountFailIfReadingExternalIdsFails() throws Exception {
- externalIdReader.setFailOnLoad(true);
-
- // update external ID branch so that external IDs need to be reloaded
- insertExtIdBehindGerritsBack(ExternalId.create("foo", "bar", admin.id));
-
- exception.expect(IOException.class);
- externalIds.byAccount(admin.id);
- }
-
- @Test
- public void byEmailFailIfReadingExternalIdsFails() throws Exception {
- externalIdReader.setFailOnLoad(true);
-
- // update external ID branch so that external IDs need to be reloaded
- insertExtIdBehindGerritsBack(ExternalId.create("foo", "bar", admin.id));
-
- exception.expect(IOException.class);
- externalIds.byEmail(admin.email);
- }
-
- @Test
- public void byAccountUpdateExternalIdsBehindGerritsBack() throws Exception {
- Set<ExternalId> expectedExternalIds = new HashSet<>(externalIds.byAccount(admin.id));
- ExternalId newExtId = ExternalId.create("foo", "bar", admin.id);
- insertExtIdBehindGerritsBack(newExtId);
- expectedExternalIds.add(newExtId);
- assertThat(externalIds.byAccount(admin.id)).containsExactlyElementsIn(expectedExternalIds);
- }
-
- @Test
- public void unsetEmail() throws Exception {
- ExternalId extId = ExternalId.createWithEmail("x", "1", user.id, "x@example.com");
- extIdsUpdate.create().insert(extId);
-
- ExternalId extIdWithoutEmail = ExternalId.create("x", "1", user.id);
- extIdsUpdate.create().upsert(extIdWithoutEmail);
-
- assertThat(externalIds.get(extId.key())).isEqualTo(extIdWithoutEmail);
- }
-
- @Test
- public void unsetHttpPassword() throws Exception {
- ExternalId extId =
- ExternalId.createWithPassword(ExternalId.Key.create("y", "1"), user.id, null, "secret");
- extIdsUpdate.create().insert(extId);
-
- ExternalId extIdWithoutPassword = ExternalId.create("y", "1", user.id);
- extIdsUpdate.create().upsert(extIdWithoutPassword);
-
- assertThat(externalIds.get(extId.key())).isEqualTo(extIdWithoutPassword);
- }
-
- private void insertExtIdBehindGerritsBack(ExternalId extId) throws Exception {
- try (Repository repo = repoManager.openRepository(allUsers);
- RevWalk rw = new RevWalk(repo);
- ObjectInserter ins = repo.newObjectInserter()) {
- ObjectId rev = ExternalIdReader.readRevision(repo);
- NoteMap noteMap = ExternalIdReader.readNoteMap(rw, rev);
- ExternalIdsUpdate.insert(rw, ins, noteMap, extId);
- ExternalIdsUpdate.commit(
- allUsers,
- repo,
- rw,
- ins,
- rev,
- noteMap,
- "insert new ID",
- serverIdent.get(),
- serverIdent.get(),
- null,
- GitReferenceUpdated.DISABLED);
- }
- }
-
- private void addExtId(TestRepository<?> testRepo, ExternalId... extIds)
- throws IOException, OrmDuplicateKeyException, ConfigInvalidException {
- ObjectId rev = ExternalIdReader.readRevision(testRepo.getRepository());
-
- try (ObjectInserter ins = testRepo.getRepository().newObjectInserter()) {
- NoteMap noteMap = ExternalIdReader.readNoteMap(testRepo.getRevWalk(), rev);
- for (ExternalId extId : extIds) {
- ExternalIdsUpdate.insert(testRepo.getRevWalk(), ins, noteMap, extId);
- }
-
- ExternalIdsUpdate.commit(
- allUsers,
- testRepo.getRepository(),
- testRepo.getRevWalk(),
- ins,
- rev,
- noteMap,
- "Add external ID",
- admin.getIdent(),
- admin.getIdent(),
- null,
- GitReferenceUpdated.DISABLED);
- }
- }
-
- private List<AccountExternalIdInfo> toExternalIdInfos(Collection<ExternalId> extIds) {
- return extIds.stream().map(this::toExternalIdInfo).collect(toList());
- }
-
- private AccountExternalIdInfo toExternalIdInfo(ExternalId extId) {
- AccountExternalIdInfo info = new AccountExternalIdInfo();
- info.identity = extId.key().get();
- info.emailAddress = extId.email();
- info.canDelete = !extId.isScheme(SCHEME_USERNAME) ? true : null;
- info.trusted =
- extId.isScheme(SCHEME_MAILTO)
- || extId.isScheme(SCHEME_UUID)
- || extId.isScheme(SCHEME_USERNAME)
- ? true
- : null;
- return info;
- }
-
- private void allowPushOfExternalIds() throws IOException, ConfigInvalidException {
- grant(allUsers, RefNames.REFS_EXTERNAL_IDS, Permission.READ);
- grant(allUsers, RefNames.REFS_EXTERNAL_IDS, Permission.PUSH);
- }
-
- private void assertRefUpdateFailure(RemoteRefUpdate update, String msg) {
- assertThat(update.getStatus()).isEqualTo(Status.REJECTED_OTHER_REASON);
- assertThat(update.getMessage()).contains(msg);
- }
-}