Merge "Add more test coverage for ListFiles"
diff --git a/Documentation/rest-api-accounts.txt b/Documentation/rest-api-accounts.txt
index f55d04a..dbb044f 100644
--- a/Documentation/rest-api-accounts.txt
+++ b/Documentation/rest-api-accounts.txt
@@ -2128,6 +2128,8 @@
 |`registered_on`     ||
 The link:rest-api.html#timestamp[timestamp] of when the account was
 registered.
+|`inactive`          |not set if `false`|
+Whether the account is inactive.
 |=================================
 
 [[account-external-id-info]]
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AccountIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AccountIT.java
index 50bc0be..9a1100f 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AccountIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AccountIT.java
@@ -591,7 +591,7 @@
     assertThat(getEmails()).contains(email);
 
     gApi.accounts().self().deleteEmail(email);
-    accountIndexedCounter.assertReindexOf(admin, 2); // for each deleted external ID once
+    accountIndexedCounter.assertReindexOf(admin);
 
     resetCurrentApiUser();
     assertThat(getEmails()).doesNotContain(email);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java
index a6f1e2b..01aa131 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java
@@ -15,6 +15,7 @@
 package com.google.gerrit.server.account;
 
 import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
 import com.google.gerrit.audit.AuditService;
 import com.google.gerrit.common.data.AccessSection;
 import com.google.gerrit.common.data.GlobalCapability;
@@ -412,45 +413,67 @@
   }
 
   /**
-   * Unlink an authentication identity from an existing account.
+   * Unlink an external identity from an existing account.
    *
-   * @param from account to unlink the identity from.
-   * @param who the identity to delete
-   * @return the result of unlinking the identity from the user.
-   * @throws AccountException the identity belongs to a different account, or it cannot be unlinked
-   *     at this time.
+   * @param from account to unlink the external identity from
+   * @param extIdKey the key of the external ID that should be deleted
+   * @throws AccountException the identity belongs to a different account, or the identity was not
+   *     found
    */
-  public AuthResult unlink(Account.Id from, AuthRequest who)
+  public void unlink(Account.Id from, ExternalId.Key extIdKey)
       throws AccountException, OrmException, IOException, ConfigInvalidException {
+    unlink(from, ImmutableList.of(extIdKey));
+  }
+
+  /**
+   * Unlink an external identities from an existing account.
+   *
+   * @param from account to unlink the external identity from
+   * @param extIdKeys the keys of the external IDs that should be deleted
+   * @throws AccountException any of the identity belongs to a different account, or any of the
+   *     identity was not found
+   */
+  public void unlink(Account.Id from, Collection<ExternalId.Key> extIdKeys)
+      throws AccountException, OrmException, IOException, ConfigInvalidException {
+    if (extIdKeys.isEmpty()) {
+      return;
+    }
+
     try (ReviewDb db = schema.open()) {
-      ExternalId extId = externalIds.get(who.getExternalIdKey());
-      if (extId != null) {
-        if (!extId.accountId().equals(from)) {
-          throw new AccountException(
-              "Identity '" + who.getExternalIdKey().get() + "' in use by another account");
+      List<ExternalId> extIds = new ArrayList<>(extIdKeys.size());
+      for (ExternalId.Key extIdKey : extIdKeys) {
+        ExternalId extId = externalIds.get(extIdKey);
+        if (extId != null) {
+          if (!extId.accountId().equals(from)) {
+            throw new AccountException(
+                "Identity '" + extIdKey.get() + "' in use by another account");
+          }
+          extIds.add(extId);
+        } else {
+          throw new AccountException("Identity '" + extIdKey.get() + "' not found");
         }
-        externalIdsUpdateFactory.create().delete(extId);
-
-        if (who.getEmailAddress() != null) {
-          accountsUpdateFactory
-              .create()
-              .update(
-                  db,
-                  from,
-                  a -> {
-                    if (a.getPreferredEmail() != null
-                        && a.getPreferredEmail().equals(who.getEmailAddress())) {
-                      a.setPreferredEmail(null);
-                    }
-                  });
-          byEmailCache.evict(who.getEmailAddress());
-        }
-
-      } else {
-        throw new AccountException("Identity '" + who.getExternalIdKey().get() + "' not found");
       }
 
-      return new AuthResult(from, who.getExternalIdKey(), false);
+      externalIdsUpdateFactory.create().delete(extIds);
+
+      if (extIds.stream().anyMatch(e -> e.email() != null)) {
+        accountsUpdateFactory
+            .create()
+            .update(
+                db,
+                from,
+                a -> {
+                  if (a.getPreferredEmail() != null) {
+                    for (ExternalId extId : extIds) {
+                      if (a.getPreferredEmail().equals(extId.email())) {
+                        a.setPreferredEmail(null);
+                        break;
+                      }
+                    }
+                  }
+                });
+        extIds.stream().forEach(e -> byEmailCache.evict(e.email()));
+      }
     }
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/DeleteEmail.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/DeleteEmail.java
index ca56eb1..aec3a14 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/DeleteEmail.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/DeleteEmail.java
@@ -92,11 +92,8 @@
     }
 
     try {
-      for (ExternalId extId : extIds) {
-        AuthRequest authRequest = new AuthRequest(extId.key());
-        authRequest.setEmailAddress(email);
-        accountManager.unlink(user.getAccountId(), authRequest);
-      }
+      accountManager.unlink(
+          user.getAccountId(), extIds.stream().map(e -> e.key()).collect(toSet()));
     } catch (AccountException e) {
       throw new ResourceConflictException(e.getMessage());
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/DeleteExternalIds.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/DeleteExternalIds.java
index 31679a6..72c1a41 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/DeleteExternalIds.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/DeleteExternalIds.java
@@ -16,6 +16,7 @@
 
 import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_USERNAME;
 import static java.util.stream.Collectors.toMap;
+import static java.util.stream.Collectors.toSet;
 
 import com.google.gerrit.extensions.restapi.BadRequestException;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
@@ -96,11 +97,8 @@
     }
 
     try {
-      for (ExternalId extId : toDelete) {
-        AuthRequest authRequest = new AuthRequest(extId.key());
-        authRequest.setEmailAddress(extId.email());
-        accountManager.unlink(extId.accountId(), authRequest);
-      }
+      accountManager.unlink(
+          resource.getUser().getAccountId(), toDelete.stream().map(e -> e.key()).collect(toSet()));
     } catch (AccountException e) {
       throw new ResourceConflictException(e.getMessage());
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetDetail.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetDetail.java
index 9eafec0..30eb377 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetDetail.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetDetail.java
@@ -42,6 +42,7 @@
     Account a = rsrc.getUser().getAccount();
     AccountDetailInfo info = new AccountDetailInfo(a.getId().get());
     info.registeredOn = a.getRegisteredOn();
+    info.inactive = !a.isActive() ? true : null;
     try {
       directory.fillAccountInfo(Collections.singleton(info), EnumSet.allOf(FillOptions.class));
     } catch (DirectoryException e) {
@@ -53,6 +54,7 @@
 
   public static class AccountDetailInfo extends AccountInfo {
     public Timestamp registeredOn;
+    public Boolean inactive;
 
     public AccountDetailInfo(Integer id) {
       super(id);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MetaDataUpdate.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MetaDataUpdate.java
index b057c92..5693c59 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MetaDataUpdate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MetaDataUpdate.java
@@ -93,7 +93,7 @@
      * <pre>
      * <code>
      *   try (Repository repo = repoMgr.openRepository(allUsersName);
-     *       RevWalk rw = new RevWalk(repo) {
+     *       RevWalk rw = new RevWalk(repo)) {
      *     BatchRefUpdate batchUpdate = repo.getRefDatabase().newBatchUpdate();
      *     // WRONG: create the MetaDataUpdate instance here and reuse it for
      *     //        all updates in the loop
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ListTags.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ListTags.java
index 8734911..4d1f808 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ListTags.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ListTags.java
@@ -15,7 +15,6 @@
 package com.google.gerrit.server.project;
 
 import com.google.common.collect.ImmutableMap;
-import com.google.gerrit.common.Nullable;
 import com.google.gerrit.extensions.api.projects.TagInfo;
 import com.google.gerrit.extensions.common.WebLinkInfo;
 import com.google.gerrit.extensions.restapi.BadRequestException;
@@ -27,7 +26,6 @@
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.WebLinks;
 import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.git.SearchingChangeCacheImpl;
 import com.google.gerrit.server.git.VisibleRefFilter;
 import com.google.gerrit.server.permissions.PermissionBackend;
 import com.google.gerrit.server.permissions.RefPermission;
@@ -55,7 +53,6 @@
   private final PermissionBackend permissionBackend;
   private final Provider<CurrentUser> user;
   private final VisibleRefFilter.Factory refFilterFactory;
-  @Nullable private final SearchingChangeCacheImpl changeCache;
   private final WebLinks links;
 
   @Option(
@@ -109,13 +106,11 @@
       PermissionBackend permissionBackend,
       Provider<CurrentUser> user,
       VisibleRefFilter.Factory refFilterFactory,
-      @Nullable SearchingChangeCacheImpl changeCache,
       WebLinks webLinks) {
     this.repoManager = repoManager;
     this.permissionBackend = permissionBackend;
     this.user = user;
     this.refFilterFactory = refFilterFactory;
-    this.changeCache = changeCache;
     this.links = webLinks;
   }