Merge "Persist group cache by uuid"
This commit is contained in:
		@@ -815,6 +815,7 @@ Default is 1024 for most caches, except:
 | 
			
		||||
* `"groups"`: default is unlimited
 | 
			
		||||
* `"groups_byname"`: default is unlimited
 | 
			
		||||
* `"groups_byuuid"`: default is unlimited
 | 
			
		||||
* `"groups_byuuid_persisted"`: default is `1g` (1 GiB of disk space)
 | 
			
		||||
* `"plugin_resources"`: default is 2m (2 MiB of memory)
 | 
			
		||||
 | 
			
		||||
+
 | 
			
		||||
@@ -1038,6 +1039,17 @@ unlimited.
 | 
			
		||||
External group membership obtained from LDAP is cached under
 | 
			
		||||
`"ldap_groups"`.
 | 
			
		||||
 | 
			
		||||
cache `"groups_byuuid_persisted"`::
 | 
			
		||||
+
 | 
			
		||||
Caches the basic group information of internal groups by group UUID,
 | 
			
		||||
including the group owner, name, and description.
 | 
			
		||||
+
 | 
			
		||||
This is the persisted version of `groups_byuuid` cache. The intention of this
 | 
			
		||||
cache is to have an in-memory size of 0.
 | 
			
		||||
+
 | 
			
		||||
External group membership obtained from LDAP is cached under
 | 
			
		||||
`"ldap_groups"`.
 | 
			
		||||
 | 
			
		||||
cache `"groups_bymember"`::
 | 
			
		||||
+
 | 
			
		||||
Caches the groups which contain a specific member (account). If direct
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,16 @@ import com.google.common.cache.LoadingCache;
 | 
			
		||||
import com.google.common.flogger.FluentLogger;
 | 
			
		||||
import com.google.gerrit.entities.AccountGroup;
 | 
			
		||||
import com.google.gerrit.entities.InternalGroup;
 | 
			
		||||
import com.google.gerrit.entities.RefNames;
 | 
			
		||||
import com.google.gerrit.proto.Protos;
 | 
			
		||||
import com.google.gerrit.server.cache.CacheModule;
 | 
			
		||||
import com.google.gerrit.server.cache.proto.Cache;
 | 
			
		||||
import com.google.gerrit.server.cache.serialize.CacheSerializer;
 | 
			
		||||
import com.google.gerrit.server.cache.serialize.ObjectIdConverter;
 | 
			
		||||
import com.google.gerrit.server.cache.serialize.ProtobufSerializer;
 | 
			
		||||
import com.google.gerrit.server.cache.serialize.entities.InternalGroupSerializer;
 | 
			
		||||
import com.google.gerrit.server.config.AllUsersName;
 | 
			
		||||
import com.google.gerrit.server.git.GitRepositoryManager;
 | 
			
		||||
import com.google.gerrit.server.group.db.Groups;
 | 
			
		||||
import com.google.gerrit.server.logging.Metadata;
 | 
			
		||||
import com.google.gerrit.server.logging.TraceContext;
 | 
			
		||||
@@ -33,6 +42,10 @@ import com.google.inject.TypeLiteral;
 | 
			
		||||
import com.google.inject.name.Named;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
import java.util.concurrent.ExecutionException;
 | 
			
		||||
import org.bouncycastle.util.Strings;
 | 
			
		||||
import org.eclipse.jgit.lib.ObjectId;
 | 
			
		||||
import org.eclipse.jgit.lib.Ref;
 | 
			
		||||
import org.eclipse.jgit.lib.Repository;
 | 
			
		||||
 | 
			
		||||
/** Tracks group objects in memory for efficient access. */
 | 
			
		||||
@Singleton
 | 
			
		||||
@@ -42,6 +55,7 @@ public class GroupCacheImpl implements GroupCache {
 | 
			
		||||
  private static final String BYID_NAME = "groups";
 | 
			
		||||
  private static final String BYNAME_NAME = "groups_byname";
 | 
			
		||||
  private static final String BYUUID_NAME = "groups_byuuid";
 | 
			
		||||
  private static final String BYUUID_NAME_PERSISTED = "groups_byuuid_persisted";
 | 
			
		||||
 | 
			
		||||
  public static Module module() {
 | 
			
		||||
    return new CacheModule() {
 | 
			
		||||
@@ -55,9 +69,35 @@ public class GroupCacheImpl implements GroupCache {
 | 
			
		||||
            .maximumWeight(Long.MAX_VALUE)
 | 
			
		||||
            .loader(ByNameLoader.class);
 | 
			
		||||
 | 
			
		||||
        // We split the group cache into two parts for performance reasons:
 | 
			
		||||
        // 1) An in-memory part that has only the group ref uuid as key.
 | 
			
		||||
        // 2) A persisted part that has the group ref uuid and sha1 of the ref as key.
 | 
			
		||||
        //
 | 
			
		||||
        // When loading dashboards or returning change query results we potentially
 | 
			
		||||
        // need to access many groups.
 | 
			
		||||
        // We want the persisted cache to be immutable and we want it to be impossible that a
 | 
			
		||||
        // value for a given key is out of date. We therefore require the sha-1 in the key. That
 | 
			
		||||
        // is in line with the rest of the caches in Gerrit.
 | 
			
		||||
        //
 | 
			
		||||
        // Splitting the cache into two chunks internally in this class allows us to retain
 | 
			
		||||
        // the existing performance guarantees of not requiring reads for the repo for values
 | 
			
		||||
        // cached in-memory but also to persist the cache which leads to a much improved
 | 
			
		||||
        // cold-start behavior and in-memory miss latency.
 | 
			
		||||
 | 
			
		||||
        cache(BYUUID_NAME, String.class, new TypeLiteral<Optional<InternalGroup>>() {})
 | 
			
		||||
            .maximumWeight(Long.MAX_VALUE)
 | 
			
		||||
            .loader(ByUUIDLoader.class);
 | 
			
		||||
            .loader(ByUUIDInMemoryLoader.class);
 | 
			
		||||
 | 
			
		||||
        persist(
 | 
			
		||||
                BYUUID_NAME_PERSISTED,
 | 
			
		||||
                Cache.GroupKeyProto.class,
 | 
			
		||||
                new TypeLiteral<InternalGroup>() {})
 | 
			
		||||
            .loader(PersistedByUUIDLoader.class)
 | 
			
		||||
            .keySerializer(new ProtobufSerializer<>(Cache.GroupKeyProto.parser()))
 | 
			
		||||
            .valueSerializer(PersistedInternalGroupSerializer.INSTANCE)
 | 
			
		||||
            .diskLimit(1 << 30) // 1 GiB
 | 
			
		||||
            .version(1)
 | 
			
		||||
            .maximumWeight(0);
 | 
			
		||||
 | 
			
		||||
        bind(GroupCacheImpl.class);
 | 
			
		||||
        bind(GroupCache.class).to(GroupCacheImpl.class);
 | 
			
		||||
@@ -150,7 +190,7 @@ public class GroupCacheImpl implements GroupCache {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Optional<InternalGroup> load(AccountGroup.Id key) throws Exception {
 | 
			
		||||
      try (TraceTimer timer =
 | 
			
		||||
      try (TraceTimer ignored =
 | 
			
		||||
          TraceContext.newTimer(
 | 
			
		||||
              "Loading group by ID", Metadata.builder().groupId(key.get()).build())) {
 | 
			
		||||
        return groupQueryProvider.get().byId(key);
 | 
			
		||||
@@ -168,7 +208,7 @@ public class GroupCacheImpl implements GroupCache {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Optional<InternalGroup> load(String name) throws Exception {
 | 
			
		||||
      try (TraceTimer timer =
 | 
			
		||||
      try (TraceTimer ignored =
 | 
			
		||||
          TraceContext.newTimer(
 | 
			
		||||
              "Loading group by name", Metadata.builder().groupName(name).build())) {
 | 
			
		||||
        return groupQueryProvider.get().byName(AccountGroup.nameKey(name));
 | 
			
		||||
@@ -176,21 +216,89 @@ public class GroupCacheImpl implements GroupCache {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static class ByUUIDLoader extends CacheLoader<String, Optional<InternalGroup>> {
 | 
			
		||||
    private final Groups groups;
 | 
			
		||||
  static class ByUUIDInMemoryLoader extends CacheLoader<String, Optional<InternalGroup>> {
 | 
			
		||||
    private final LoadingCache<Cache.GroupKeyProto, InternalGroup> persistedCache;
 | 
			
		||||
    private final GitRepositoryManager repoManager;
 | 
			
		||||
    private final AllUsersName allUsersName;
 | 
			
		||||
 | 
			
		||||
    @Inject
 | 
			
		||||
    ByUUIDLoader(Groups groups) {
 | 
			
		||||
      this.groups = groups;
 | 
			
		||||
    ByUUIDInMemoryLoader(
 | 
			
		||||
        @Named(BYUUID_NAME_PERSISTED)
 | 
			
		||||
            LoadingCache<Cache.GroupKeyProto, InternalGroup> persistedCache,
 | 
			
		||||
        GitRepositoryManager repoManager,
 | 
			
		||||
        AllUsersName allUsersName) {
 | 
			
		||||
      this.persistedCache = persistedCache;
 | 
			
		||||
      this.repoManager = repoManager;
 | 
			
		||||
      this.allUsersName = allUsersName;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Optional<InternalGroup> load(String uuid) throws Exception {
 | 
			
		||||
      try (TraceTimer timer =
 | 
			
		||||
          TraceContext.newTimer(
 | 
			
		||||
              "Loading group by UUID", Metadata.builder().groupUuid(uuid).build())) {
 | 
			
		||||
        return groups.getGroup(AccountGroup.uuid(uuid));
 | 
			
		||||
      try (TraceTimer ignored =
 | 
			
		||||
              TraceContext.newTimer(
 | 
			
		||||
                  "Loading group from serialized cache",
 | 
			
		||||
                  Metadata.builder().groupUuid(uuid).build());
 | 
			
		||||
          Repository allUsers = repoManager.openRepository(allUsersName)) {
 | 
			
		||||
        String ref = RefNames.refsGroups(AccountGroup.uuid(uuid));
 | 
			
		||||
        Ref sha1 = allUsers.exactRef(ref);
 | 
			
		||||
        if (sha1 == null) {
 | 
			
		||||
          return Optional.empty();
 | 
			
		||||
        }
 | 
			
		||||
        Cache.GroupKeyProto key =
 | 
			
		||||
            Cache.GroupKeyProto.newBuilder()
 | 
			
		||||
                .setUuid(uuid)
 | 
			
		||||
                .setRevision(ObjectIdConverter.create().toByteString(sha1.getObjectId()))
 | 
			
		||||
                .build();
 | 
			
		||||
        return Optional.of(persistedCache.get(key));
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static class PersistedByUUIDLoader extends CacheLoader<Cache.GroupKeyProto, InternalGroup> {
 | 
			
		||||
    private final Groups groups;
 | 
			
		||||
 | 
			
		||||
    @Inject
 | 
			
		||||
    PersistedByUUIDLoader(Groups groups) {
 | 
			
		||||
      this.groups = groups;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public InternalGroup load(Cache.GroupKeyProto key) throws Exception {
 | 
			
		||||
      try (TraceTimer ignored =
 | 
			
		||||
          TraceContext.newTimer(
 | 
			
		||||
              "Loading group by UUID", Metadata.builder().groupUuid(key.getUuid()).build())) {
 | 
			
		||||
        ObjectId sha1 = ObjectIdConverter.create().fromByteString(key.getRevision());
 | 
			
		||||
        Optional<InternalGroup> loadedGroup =
 | 
			
		||||
            groups.getGroup(AccountGroup.uuid(key.getUuid()), sha1);
 | 
			
		||||
        if (!loadedGroup.isPresent()) {
 | 
			
		||||
          throw new IllegalStateException(
 | 
			
		||||
              String.format(
 | 
			
		||||
                  "group %s should have the sha-1 %s, but " + "it was not found",
 | 
			
		||||
                  key.getUuid(), sha1.getName()));
 | 
			
		||||
        }
 | 
			
		||||
        return loadedGroup.get();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private enum PersistedInternalGroupSerializer implements CacheSerializer<InternalGroup> {
 | 
			
		||||
    INSTANCE;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public byte[] serialize(InternalGroup value) {
 | 
			
		||||
      if (value == null) {
 | 
			
		||||
        return new byte[0];
 | 
			
		||||
      }
 | 
			
		||||
      return Protos.toByteArray(InternalGroupSerializer.serialize(value));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public InternalGroup deserialize(byte[] in) {
 | 
			
		||||
      if (Strings.fromByteArray(in).isEmpty()) {
 | 
			
		||||
        return null;
 | 
			
		||||
      }
 | 
			
		||||
      return InternalGroupSerializer.deserialize(
 | 
			
		||||
          Protos.parseUnchecked(Cache.InternalGroupProto.parser(), in));
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										82
									
								
								java/com/google/gerrit/server/cache/serialize/entities/InternalGroupSerializer.java
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								java/com/google/gerrit/server/cache/serialize/entities/InternalGroupSerializer.java
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
			
		||||
// Copyright (C) 2021 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.server.cache.serialize.entities;
 | 
			
		||||
 | 
			
		||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
 | 
			
		||||
 | 
			
		||||
import com.google.gerrit.entities.Account;
 | 
			
		||||
import com.google.gerrit.entities.AccountGroup;
 | 
			
		||||
import com.google.gerrit.entities.InternalGroup;
 | 
			
		||||
import com.google.gerrit.server.cache.proto.Cache;
 | 
			
		||||
import com.google.gerrit.server.cache.serialize.ObjectIdConverter;
 | 
			
		||||
import java.sql.Timestamp;
 | 
			
		||||
 | 
			
		||||
/** Helper to (de)serialize values for caches. */
 | 
			
		||||
public class InternalGroupSerializer {
 | 
			
		||||
  public static InternalGroup deserialize(Cache.InternalGroupProto proto) {
 | 
			
		||||
    InternalGroup.Builder builder =
 | 
			
		||||
        InternalGroup.builder()
 | 
			
		||||
            .setId(AccountGroup.id(proto.getId()))
 | 
			
		||||
            .setNameKey(AccountGroup.nameKey(proto.getName()))
 | 
			
		||||
            .setOwnerGroupUUID(AccountGroup.uuid(proto.getOwnerGroupUuid()))
 | 
			
		||||
            .setVisibleToAll(proto.getIsVisibleToAll())
 | 
			
		||||
            .setGroupUUID(AccountGroup.uuid(proto.getGroupUuid()))
 | 
			
		||||
            .setCreatedOn(new Timestamp(proto.getCreatedOn()))
 | 
			
		||||
            .setMembers(
 | 
			
		||||
                proto.getMembersIdsList().stream()
 | 
			
		||||
                    .map(a -> Account.id(a))
 | 
			
		||||
                    .collect(toImmutableSet()))
 | 
			
		||||
            .setSubgroups(
 | 
			
		||||
                proto.getSubgroupUuidsList().stream()
 | 
			
		||||
                    .map(s -> AccountGroup.uuid(s))
 | 
			
		||||
                    .collect(toImmutableSet()));
 | 
			
		||||
 | 
			
		||||
    if (!proto.getDescription().isEmpty()) {
 | 
			
		||||
      builder.setDescription(proto.getDescription());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!proto.getRefState().isEmpty()) {
 | 
			
		||||
      builder.setRefState(ObjectIdConverter.create().fromByteString(proto.getRefState()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return builder.build();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static Cache.InternalGroupProto serialize(InternalGroup autoValue) {
 | 
			
		||||
    Cache.InternalGroupProto.Builder builder =
 | 
			
		||||
        Cache.InternalGroupProto.newBuilder()
 | 
			
		||||
            .setId(autoValue.getId().get())
 | 
			
		||||
            .setName(autoValue.getName())
 | 
			
		||||
            .setOwnerGroupUuid(autoValue.getOwnerGroupUUID().get())
 | 
			
		||||
            .setIsVisibleToAll(autoValue.isVisibleToAll())
 | 
			
		||||
            .setGroupUuid(autoValue.getGroupUUID().get())
 | 
			
		||||
            .setCreatedOn(autoValue.getCreatedOn().getTime());
 | 
			
		||||
 | 
			
		||||
    autoValue.getMembers().stream().forEach(m -> builder.addMembersIds(m.get()));
 | 
			
		||||
    autoValue.getSubgroups().stream().forEach(s -> builder.addSubgroupUuids(s.get()));
 | 
			
		||||
 | 
			
		||||
    if (autoValue.getDescription() != null) {
 | 
			
		||||
      builder.setDescription(autoValue.getDescription());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (autoValue.getRefState() != null) {
 | 
			
		||||
      builder.setRefState(ObjectIdConverter.create().toByteString(autoValue.getRefState()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return builder.build();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private InternalGroupSerializer() {}
 | 
			
		||||
}
 | 
			
		||||
@@ -24,6 +24,7 @@ import com.google.common.base.Splitter;
 | 
			
		||||
import com.google.common.base.Strings;
 | 
			
		||||
import com.google.common.collect.ImmutableSet;
 | 
			
		||||
import com.google.common.collect.Streams;
 | 
			
		||||
import com.google.gerrit.common.Nullable;
 | 
			
		||||
import com.google.gerrit.entities.Account;
 | 
			
		||||
import com.google.gerrit.entities.AccountGroup;
 | 
			
		||||
import com.google.gerrit.entities.InternalGroup;
 | 
			
		||||
@@ -156,7 +157,7 @@ public class GroupConfig extends VersionedMetaData {
 | 
			
		||||
      Project.NameKey projectName,
 | 
			
		||||
      Repository repository,
 | 
			
		||||
      AccountGroup.UUID groupUuid,
 | 
			
		||||
      ObjectId groupRefObjectId)
 | 
			
		||||
      @Nullable ObjectId groupRefObjectId)
 | 
			
		||||
      throws IOException, ConfigInvalidException {
 | 
			
		||||
    GroupConfig groupConfig = new GroupConfig(groupUuid);
 | 
			
		||||
    if (groupRefObjectId == null) {
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@ package com.google.gerrit.server.group.db;
 | 
			
		||||
import com.google.common.collect.ImmutableList;
 | 
			
		||||
import com.google.common.collect.ImmutableSet;
 | 
			
		||||
import com.google.common.flogger.FluentLogger;
 | 
			
		||||
import com.google.gerrit.common.Nullable;
 | 
			
		||||
import com.google.gerrit.entities.AccountGroup;
 | 
			
		||||
import com.google.gerrit.entities.AccountGroupByIdAudit;
 | 
			
		||||
import com.google.gerrit.entities.AccountGroupMemberAudit;
 | 
			
		||||
@@ -79,6 +80,23 @@ public class Groups {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Returns the {@code InternalGroup} for the specified UUID and groupRefObjectId
 | 
			
		||||
   *
 | 
			
		||||
   * @param groupUuid the UUID of the group
 | 
			
		||||
   * @param groupRefObjectId the ref revision of this group
 | 
			
		||||
   * @return the found {@code InternalGroup} if it exists, or else an empty {@code Optional}
 | 
			
		||||
   * @throws IOException if the group couldn't be retrieved from NoteDb
 | 
			
		||||
   * @throws ConfigInvalidException if the group couldn't be retrieved from NoteDb
 | 
			
		||||
   */
 | 
			
		||||
  public Optional<InternalGroup> getGroup(
 | 
			
		||||
      AccountGroup.UUID groupUuid, @Nullable ObjectId groupRefObjectId)
 | 
			
		||||
      throws IOException, ConfigInvalidException {
 | 
			
		||||
    try (Repository allUsersRepo = repoManager.openRepository(allUsersName)) {
 | 
			
		||||
      return getGroupFromNoteDb(allUsersName, allUsersRepo, groupUuid, groupRefObjectId);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Loads an internal group from NoteDb using the group UUID. This method returns the latest state
 | 
			
		||||
   * of the internal group.
 | 
			
		||||
@@ -97,7 +115,7 @@ public class Groups {
 | 
			
		||||
      AllUsersName allUsersName,
 | 
			
		||||
      Repository allUsersRepository,
 | 
			
		||||
      AccountGroup.UUID uuid,
 | 
			
		||||
      ObjectId groupRefObjectId)
 | 
			
		||||
      @Nullable ObjectId groupRefObjectId)
 | 
			
		||||
      throws IOException, ConfigInvalidException {
 | 
			
		||||
    GroupConfig groupConfig =
 | 
			
		||||
        GroupConfig.loadForGroup(allUsersName, allUsersRepository, uuid, groupRefObjectId);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										61
									
								
								javatests/com/google/gerrit/server/cache/serialize/entities/InternalGroupSerializerTest.java
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								javatests/com/google/gerrit/server/cache/serialize/entities/InternalGroupSerializerTest.java
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,61 @@
 | 
			
		||||
// Copyright (C) 2021 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.server.cache.serialize.entities;
 | 
			
		||||
 | 
			
		||||
import static com.google.common.truth.Truth.assertThat;
 | 
			
		||||
import static com.google.gerrit.server.cache.serialize.entities.InternalGroupSerializer.deserialize;
 | 
			
		||||
import static com.google.gerrit.server.cache.serialize.entities.InternalGroupSerializer.serialize;
 | 
			
		||||
 | 
			
		||||
import com.google.common.collect.ImmutableSet;
 | 
			
		||||
import com.google.gerrit.entities.Account;
 | 
			
		||||
import com.google.gerrit.entities.AccountGroup;
 | 
			
		||||
import com.google.gerrit.entities.InternalGroup;
 | 
			
		||||
import com.google.gerrit.server.util.time.TimeUtil;
 | 
			
		||||
import org.eclipse.jgit.lib.ObjectId;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
public class InternalGroupSerializerTest {
 | 
			
		||||
  static final InternalGroup MINIMAL_VALUES_SET =
 | 
			
		||||
      InternalGroup.builder()
 | 
			
		||||
          .setId(AccountGroup.id(123456))
 | 
			
		||||
          .setNameKey(AccountGroup.nameKey("group name"))
 | 
			
		||||
          .setOwnerGroupUUID(AccountGroup.uuid("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"))
 | 
			
		||||
          .setVisibleToAll(false)
 | 
			
		||||
          .setGroupUUID(AccountGroup.uuid("deadbeefdeadbeefdeadbeefdeadbeef12345678"))
 | 
			
		||||
          .setCreatedOn(TimeUtil.nowTs())
 | 
			
		||||
          .setMembers(ImmutableSet.of(Account.id(123), Account.id(321)))
 | 
			
		||||
          .setSubgroups(
 | 
			
		||||
              ImmutableSet.of(
 | 
			
		||||
                  AccountGroup.uuid("87654321deadbeefdeadbeefdeadbeefdeadbeef"),
 | 
			
		||||
                  AccountGroup.uuid("deadbeefdeadbeefdeadbeefdeadbeef87654321")))
 | 
			
		||||
          .build();
 | 
			
		||||
 | 
			
		||||
  static final InternalGroup ALL_VALUES_SET =
 | 
			
		||||
      MINIMAL_VALUES_SET
 | 
			
		||||
          .toBuilder()
 | 
			
		||||
          .setDescription("description")
 | 
			
		||||
          .setRefState(ObjectId.fromString("12345678deadbeefdeadbeefdeadbeefdeadbeef"))
 | 
			
		||||
          .build();
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void roundTrip() {
 | 
			
		||||
    assertThat(deserialize(serialize(ALL_VALUES_SET))).isEqualTo(ALL_VALUES_SET);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void roundTripWithMinimalValues() {
 | 
			
		||||
    assertThat(deserialize(serialize(MINIMAL_VALUES_SET))).isEqualTo(MINIMAL_VALUES_SET);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -286,6 +286,29 @@ message AllExternalGroupsProto {
 | 
			
		||||
  repeated ExternalGroupProto external_group = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Serialized key for com.google.gerrit.server.account.GroupCacheImpl.
 | 
			
		||||
// Next ID: 3
 | 
			
		||||
message GroupKeyProto {
 | 
			
		||||
  string uuid = 1;
 | 
			
		||||
  bytes revision = 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Serialized form of com.google.gerrit.entities.InternalGroup.
 | 
			
		||||
// Next ID: 11
 | 
			
		||||
message InternalGroupProto {
 | 
			
		||||
  int32 id = 1;
 | 
			
		||||
  string name = 2;
 | 
			
		||||
  string description = 3;
 | 
			
		||||
  string owner_group_uuid = 4;
 | 
			
		||||
  bool is_visible_to_all = 5;
 | 
			
		||||
  string group_uuid = 6;
 | 
			
		||||
  int64 created_on = 7;
 | 
			
		||||
  repeated int32 members_ids = 8;
 | 
			
		||||
  repeated string subgroup_uuids = 9;
 | 
			
		||||
  bytes ref_state = 10;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Key for com.google.gerrit.server.git.PureRevertCache.
 | 
			
		||||
// Next ID: 4
 | 
			
		||||
message PureRevertKeyProto {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user