Fix set preferences REST handler for partially filled input record
It was erroneously assumed, that all attributes for input record are always filled. This may not be the case. When input record only partially filled, the current settings must be read from the git backend, without nullifying false values and merged with partially filled input record. Only after this merging new values can be written to the git backend. Change-Id: Iff5763fd408918622d6e82ac122bf09a99d9aaba
This commit is contained in:
parent
494af1d177
commit
ddd8ec8d06
@ -69,6 +69,18 @@ public class EditPreferencesIT extends AbstractDaemonTest {
|
|||||||
assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
|
assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
|
||||||
EditPreferencesInfo info = getEditPrefInfo(r);
|
EditPreferencesInfo info = getEditPrefInfo(r);
|
||||||
assertEditPreferences(info, out);
|
assertEditPreferences(info, out);
|
||||||
|
|
||||||
|
// Partially filled input record
|
||||||
|
EditPreferencesInfo in = new EditPreferencesInfo();
|
||||||
|
in.tabSize = 42;
|
||||||
|
r = adminSession.put(endPoint, in);
|
||||||
|
assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_NO_CONTENT);
|
||||||
|
|
||||||
|
r = adminSession.get(endPoint);
|
||||||
|
assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
|
||||||
|
info = getEditPrefInfo(r);
|
||||||
|
out.tabSize = in.tabSize;
|
||||||
|
assertEditPreferences(info, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
private EditPreferencesInfo getEditPrefInfo(RestResponse r)
|
private EditPreferencesInfo getEditPrefInfo(RestResponse r)
|
||||||
|
@ -19,6 +19,7 @@ import static com.google.gerrit.server.config.ConfigUtil.loadSection;
|
|||||||
import com.google.gerrit.extensions.client.EditPreferencesInfo;
|
import com.google.gerrit.extensions.client.EditPreferencesInfo;
|
||||||
import com.google.gerrit.extensions.restapi.AuthException;
|
import com.google.gerrit.extensions.restapi.AuthException;
|
||||||
import com.google.gerrit.extensions.restapi.RestReadView;
|
import com.google.gerrit.extensions.restapi.RestReadView;
|
||||||
|
import com.google.gerrit.reviewdb.client.Account;
|
||||||
import com.google.gerrit.server.CurrentUser;
|
import com.google.gerrit.server.CurrentUser;
|
||||||
import com.google.gerrit.server.config.AllUsersName;
|
import com.google.gerrit.server.config.AllUsersName;
|
||||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||||
@ -28,6 +29,7 @@ import com.google.inject.Provider;
|
|||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
|
|
||||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||||
|
import org.eclipse.jgit.errors.RepositoryNotFoundException;
|
||||||
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.lib.Repository;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -55,13 +57,21 @@ public class GetEditPreferences implements RestReadView<AccountResource> {
|
|||||||
throw new AuthException("restricted to members of Modify Accounts");
|
throw new AuthException("restricted to members of Modify Accounts");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return readFromGit(
|
||||||
|
rsrc.getUser().getAccountId(), gitMgr, allUsersName, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
static EditPreferencesInfo readFromGit(Account.Id id,
|
||||||
|
GitRepositoryManager gitMgr, AllUsersName allUsersName,
|
||||||
|
EditPreferencesInfo in) throws IOException, ConfigInvalidException,
|
||||||
|
RepositoryNotFoundException {
|
||||||
try (Repository git = gitMgr.openRepository(allUsersName)) {
|
try (Repository git = gitMgr.openRepository(allUsersName)) {
|
||||||
VersionedAccountPreferences p =
|
VersionedAccountPreferences p =
|
||||||
VersionedAccountPreferences.forUser(rsrc.getUser().getAccountId());
|
VersionedAccountPreferences.forUser(id);
|
||||||
p.load(git);
|
p.load(git);
|
||||||
|
|
||||||
return loadSection(p.getConfig(), UserConfigSections.EDIT, null,
|
return loadSection(p.getConfig(), UserConfigSections.EDIT, null,
|
||||||
new EditPreferencesInfo(), EditPreferencesInfo.defaults());
|
new EditPreferencesInfo(), EditPreferencesInfo.defaults(), in);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
package com.google.gerrit.server.account;
|
package com.google.gerrit.server.account;
|
||||||
|
|
||||||
|
import static com.google.gerrit.server.account.GetEditPreferences.readFromGit;
|
||||||
import static com.google.gerrit.server.config.ConfigUtil.storeSection;
|
import static com.google.gerrit.server.config.ConfigUtil.storeSection;
|
||||||
|
|
||||||
import com.google.gerrit.extensions.client.EditPreferencesInfo;
|
import com.google.gerrit.extensions.client.EditPreferencesInfo;
|
||||||
@ -24,6 +25,7 @@ import com.google.gerrit.extensions.restapi.RestModifyView;
|
|||||||
import com.google.gerrit.reviewdb.client.Account;
|
import com.google.gerrit.reviewdb.client.Account;
|
||||||
import com.google.gerrit.server.CurrentUser;
|
import com.google.gerrit.server.CurrentUser;
|
||||||
import com.google.gerrit.server.config.AllUsersName;
|
import com.google.gerrit.server.config.AllUsersName;
|
||||||
|
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||||
import com.google.gerrit.server.git.MetaDataUpdate;
|
import com.google.gerrit.server.git.MetaDataUpdate;
|
||||||
import com.google.gerrit.server.git.UserConfigSections;
|
import com.google.gerrit.server.git.UserConfigSections;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
@ -41,14 +43,17 @@ public class SetEditPreferences implements
|
|||||||
|
|
||||||
private final Provider<CurrentUser> self;
|
private final Provider<CurrentUser> self;
|
||||||
private final Provider<MetaDataUpdate.User> metaDataUpdateFactory;
|
private final Provider<MetaDataUpdate.User> metaDataUpdateFactory;
|
||||||
|
private final GitRepositoryManager gitMgr;
|
||||||
private final AllUsersName allUsersName;
|
private final AllUsersName allUsersName;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
SetEditPreferences(Provider<CurrentUser> self,
|
SetEditPreferences(Provider<CurrentUser> self,
|
||||||
Provider<MetaDataUpdate.User> metaDataUpdateFactory,
|
Provider<MetaDataUpdate.User> metaDataUpdateFactory,
|
||||||
|
GitRepositoryManager gitMgr,
|
||||||
AllUsersName allUsersName) {
|
AllUsersName allUsersName) {
|
||||||
this.self = self;
|
this.self = self;
|
||||||
this.metaDataUpdateFactory = metaDataUpdateFactory;
|
this.metaDataUpdateFactory = metaDataUpdateFactory;
|
||||||
|
this.gitMgr = gitMgr;
|
||||||
this.allUsersName = allUsersName;
|
this.allUsersName = allUsersName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +77,8 @@ public class SetEditPreferences implements
|
|||||||
try {
|
try {
|
||||||
prefs = VersionedAccountPreferences.forUser(accountId);
|
prefs = VersionedAccountPreferences.forUser(accountId);
|
||||||
prefs.load(md);
|
prefs.load(md);
|
||||||
storeSection(prefs.getConfig(), UserConfigSections.EDIT, null, in,
|
storeSection(prefs.getConfig(), UserConfigSections.EDIT, null,
|
||||||
|
readFromGit(accountId, gitMgr, allUsersName, in),
|
||||||
EditPreferencesInfo.defaults());
|
EditPreferencesInfo.defaults());
|
||||||
prefs.commit(md);
|
prefs.commit(md);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -314,19 +314,19 @@ public class ConfigUtil {
|
|||||||
* The loading is performed eagerly: all values are set.
|
* The loading is performed eagerly: all values are set.
|
||||||
* <p>
|
* <p>
|
||||||
* Fields marked with final or transient modifiers are skipped.
|
* Fields marked with final or transient modifiers are skipped.
|
||||||
* <p>
|
|
||||||
* Boolean fields are only set when their values are true.
|
|
||||||
*
|
*
|
||||||
* @param cfg config from which the values are loaded
|
* @param cfg config from which the values are loaded
|
||||||
* @param section section
|
* @param section section
|
||||||
* @param sub subsection
|
* @param sub subsection
|
||||||
* @param s instance of class in which the values are set
|
* @param s instance of class in which the values are set
|
||||||
* @param defaults instance of class with default values
|
* @param defaults instance of class with default values
|
||||||
|
* @param i instance to merge during the load. When present, the
|
||||||
|
* boolean fields are not nullified when their values are false
|
||||||
* @return loaded instance
|
* @return loaded instance
|
||||||
* @throws ConfigInvalidException
|
* @throws ConfigInvalidException
|
||||||
*/
|
*/
|
||||||
public static <T> T loadSection(Config cfg, String section, String sub,
|
public static <T> T loadSection(Config cfg, String section, String sub,
|
||||||
T s, T defaults) throws ConfigInvalidException {
|
T s, T defaults, T i) throws ConfigInvalidException {
|
||||||
try {
|
try {
|
||||||
for (Field f : s.getClass().getDeclaredFields()) {
|
for (Field f : s.getClass().getDeclaredFields()) {
|
||||||
if (skipField(f)) {
|
if (skipField(f)) {
|
||||||
@ -345,7 +345,7 @@ public class ConfigUtil {
|
|||||||
f.set(s, cfg.getLong(section, sub, n, (Long) d));
|
f.set(s, cfg.getLong(section, sub, n, (Long) d));
|
||||||
} else if (isBoolean(t)) {
|
} else if (isBoolean(t)) {
|
||||||
boolean b = cfg.getBoolean(section, sub, n, (Boolean) d);
|
boolean b = cfg.getBoolean(section, sub, n, (Boolean) d);
|
||||||
if (b) {
|
if (b || i != null) {
|
||||||
f.set(s, b);
|
f.set(s, b);
|
||||||
}
|
}
|
||||||
} else if (t.isEnum()) {
|
} else if (t.isEnum()) {
|
||||||
@ -353,6 +353,12 @@ public class ConfigUtil {
|
|||||||
} else {
|
} else {
|
||||||
throw new ConfigInvalidException("type is unknown: " + t.getName());
|
throw new ConfigInvalidException("type is unknown: " + t.getName());
|
||||||
}
|
}
|
||||||
|
if (i != null) {
|
||||||
|
Object o = f.get(i);
|
||||||
|
if (o != null) {
|
||||||
|
f.set(s, o);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (SecurityException | IllegalArgumentException
|
} catch (SecurityException | IllegalArgumentException
|
||||||
| IllegalAccessException e) {
|
| IllegalAccessException e) {
|
||||||
|
@ -98,7 +98,7 @@ public class ConfigUtilTest {
|
|||||||
assertThat(cfg.getString(SECT, SUB, "sd")).isNull();
|
assertThat(cfg.getString(SECT, SUB, "sd")).isNull();
|
||||||
|
|
||||||
SectionInfo out = new SectionInfo();
|
SectionInfo out = new SectionInfo();
|
||||||
ConfigUtil.loadSection(cfg, SECT, SUB, out, d);
|
ConfigUtil.loadSection(cfg, SECT, SUB, out, d, null);
|
||||||
assertThat(out.i).isEqualTo(in.i);
|
assertThat(out.i).isEqualTo(in.i);
|
||||||
assertThat(out.ii).isEqualTo(in.ii);
|
assertThat(out.ii).isEqualTo(in.ii);
|
||||||
assertThat(out.id).isEqualTo(d.id);
|
assertThat(out.id).isEqualTo(d.id);
|
||||||
@ -114,6 +114,25 @@ public class ConfigUtilTest {
|
|||||||
assertThat(out.td).isEqualTo(d.td);
|
assertThat(out.td).isEqualTo(d.td);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mergeSection() throws Exception {
|
||||||
|
SectionInfo d = SectionInfo.defaults();
|
||||||
|
Config cfg = new Config();
|
||||||
|
ConfigUtil.storeSection(cfg, SECT, SUB, d, d);
|
||||||
|
|
||||||
|
SectionInfo in = new SectionInfo();
|
||||||
|
in.i = 42;
|
||||||
|
|
||||||
|
SectionInfo out = new SectionInfo();
|
||||||
|
ConfigUtil.loadSection(cfg, SECT, SUB, out, d, in);
|
||||||
|
// Check original values preserved
|
||||||
|
assertThat(out.id).isEqualTo(d.id);
|
||||||
|
// Check merged values
|
||||||
|
assertThat(out.i).isEqualTo(in.i);
|
||||||
|
// Check that boolean attribute not nullified
|
||||||
|
assertThat(out.bb).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTimeUnit() {
|
public void testTimeUnit() {
|
||||||
assertEquals(ms(0, MILLISECONDS), parse("0"));
|
assertEquals(ms(0, MILLISECONDS), parse("0"));
|
||||||
|
Loading…
Reference in New Issue
Block a user