Merge "Fix reading empty subsections from plugin config"
diff --git a/java/com/google/gerrit/server/project/ProjectLevelConfig.java b/java/com/google/gerrit/server/project/ProjectLevelConfig.java
index 555cf4c..d82a318 100644
--- a/java/com/google/gerrit/server/project/ProjectLevelConfig.java
+++ b/java/com/google/gerrit/server/project/ProjectLevelConfig.java
@@ -132,21 +132,28 @@
 
                 for (String subsection : levelCfg.getSubsections(section)) {
                   allNames = cfg.getNames(section, subsection);
-                  for (String name : levelCfg.getNames(section, subsection)) {
-                    String[] levelValues = levelCfg.getStringList(section, subsection, name);
-                    if (allNames.contains(name) && merge) {
-                      cfg.setStringList(
-                          section,
-                          subsection,
-                          name,
-                          Streams.concat(
-                                  Arrays.stream(cfg.getStringList(section, subsection, name)),
-                                  Arrays.stream(levelValues))
-                              .sorted()
-                              .distinct()
-                              .collect(toList()));
-                    } else {
-                      cfg.setStringList(section, subsection, name, Arrays.asList(levelValues));
+
+                  Set<String> allNamesLevelCfg = levelCfg.getNames(section, subsection);
+                  if (allNamesLevelCfg.isEmpty()) {
+                    // Set empty subsection.
+                    cfg.setString(section, subsection, null, null);
+                  } else {
+                    for (String name : allNamesLevelCfg) {
+                      String[] levelValues = levelCfg.getStringList(section, subsection, name);
+                      if (allNames.contains(name) && merge) {
+                        cfg.setStringList(
+                            section,
+                            subsection,
+                            name,
+                            Streams.concat(
+                                    Arrays.stream(cfg.getStringList(section, subsection, name)),
+                                    Arrays.stream(levelValues))
+                                .sorted()
+                                .distinct()
+                                .collect(toList()));
+                      } else {
+                        cfg.setStringList(section, subsection, name, Arrays.asList(levelValues));
+                      }
                     }
                   }
                 }
diff --git a/javatests/com/google/gerrit/acceptance/rest/project/ProjectLevelConfigIT.java b/javatests/com/google/gerrit/acceptance/rest/project/ProjectLevelConfigIT.java
index 5fd55ec..ffdbd8e 100644
--- a/javatests/com/google/gerrit/acceptance/rest/project/ProjectLevelConfigIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/project/ProjectLevelConfigIT.java
@@ -22,16 +22,23 @@
 import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
 import com.google.gerrit.entities.Project;
 import com.google.gerrit.entities.RefNames;
+import com.google.gerrit.server.config.PluginConfigFactory;
 import com.google.gerrit.server.project.ProjectState;
 import com.google.inject.Inject;
 import java.util.Arrays;
 import org.eclipse.jgit.junit.TestRepository;
 import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
 import org.junit.Before;
 import org.junit.Test;
 
 public class ProjectLevelConfigIT extends AbstractDaemonTest {
+  private static final String PLUGIN_NAME = "test-plugin";
+
   @Inject private ProjectOperations projectOperations;
+  @Inject private PluginConfigFactory pluginConfigFactory;
 
   @Before
   public void setUp() throws Exception {
@@ -185,4 +192,27 @@
     ProjectState state = projectCache.get(project).get();
     assertThat(state.getConfig(configName).get().toText()).isEmpty();
   }
+
+  @Test
+  public void emptySubSectionsCanBeRead() throws Exception {
+    updatePluginConfig(project, "[section \"subsection\"]");
+    Config cfg = pluginConfigFactory.getProjectPluginConfigWithInheritance(project, PLUGIN_NAME);
+    assertThat(cfg.getSubsections("section")).containsExactly("subsection");
+  }
+
+  private void updatePluginConfig(Project.NameKey project, String pluginConfig) throws Exception {
+    try (TestRepository<Repository> testRepo =
+        new TestRepository<>(repoManager.openRepository(project))) {
+      Ref ref = testRepo.getRepository().exactRef(RefNames.REFS_CONFIG);
+      RevCommit head = testRepo.getRevWalk().parseCommit(ref.getObjectId());
+      testRepo.update(
+          RefNames.REFS_CONFIG,
+          testRepo
+              .commit()
+              .parent(head)
+              .message("Configure plugin")
+              .add(PLUGIN_NAME + ".config", pluginConfig));
+    }
+    projectCache.evict(project);
+  }
 }