// Copyright (C) 2016 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.account; import static com.google.common.truth.Truth.assertThat; import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.server.account.WatchConfig.NotifyType; import com.google.gerrit.server.account.WatchConfig.NotifyValue; import com.google.gerrit.server.account.WatchConfig.ProjectWatchKey; import com.google.gerrit.server.git.ValidationError; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.jgit.lib.Config; import org.junit.Before; import org.junit.Test; public class WatchConfigTest implements ValidationError.Sink { private List<ValidationError> validationErrors = new ArrayList<>(); @Before public void setup() { validationErrors.clear(); } @Test public void parseWatchConfig() throws Exception { Config cfg = new Config(); cfg.fromText( "[project \"myProject\"]\n" + " notify = * [ALL_COMMENTS, NEW_PATCHSETS]\n" + " notify = branch:master [NEW_CHANGES]\n" + " notify = branch:master [NEW_PATCHSETS]\n" + " notify = branch:foo []\n" + "[project \"otherProject\"]\n" + " notify = [NEW_PATCHSETS]\n" + " notify = * [NEW_PATCHSETS, ALL_COMMENTS]\n"); Map<ProjectWatchKey, Set<NotifyType>> projectWatches = WatchConfig.parse(new Account.Id(1000000), cfg, this); assertThat(validationErrors).isEmpty(); Project.NameKey myProject = new Project.NameKey("myProject"); Project.NameKey otherProject = new Project.NameKey("otherProject"); Map<ProjectWatchKey, Set<NotifyType>> expectedProjectWatches = new HashMap<>(); expectedProjectWatches.put( ProjectWatchKey.create(myProject, null), EnumSet.of(NotifyType.ALL_COMMENTS, NotifyType.NEW_PATCHSETS)); expectedProjectWatches.put( ProjectWatchKey.create(myProject, "branch:master"), EnumSet.of(NotifyType.NEW_CHANGES, NotifyType.NEW_PATCHSETS)); expectedProjectWatches.put( ProjectWatchKey.create(myProject, "branch:foo"), EnumSet.noneOf(NotifyType.class)); expectedProjectWatches.put( ProjectWatchKey.create(otherProject, null), EnumSet.of(NotifyType.NEW_PATCHSETS)); expectedProjectWatches.put( ProjectWatchKey.create(otherProject, null), EnumSet.of(NotifyType.ALL_COMMENTS, NotifyType.NEW_PATCHSETS)); assertThat(projectWatches).containsExactlyEntriesIn(expectedProjectWatches); } @Test public void parseInvalidWatchConfig() throws Exception { Config cfg = new Config(); cfg.fromText( "[project \"myProject\"]\n" + " notify = * [ALL_COMMENTS, NEW_PATCHSETS]\n" + " notify = branch:master [INVALID, NEW_CHANGES]\n" + "[project \"otherProject\"]\n" + " notify = [NEW_PATCHSETS]\n"); WatchConfig.parse(new Account.Id(1000000), cfg, this); assertThat(validationErrors).hasSize(1); assertThat(validationErrors.get(0).getMessage()) .isEqualTo( "watch.config: Invalid notify type INVALID in project watch of" + " account 1000000 for project myProject: branch:master" + " [INVALID, NEW_CHANGES]"); } @Test public void parseNotifyValue() throws Exception { assertParseNotifyValue("* []", null, EnumSet.noneOf(NotifyType.class)); assertParseNotifyValue("* [ALL_COMMENTS]", null, EnumSet.of(NotifyType.ALL_COMMENTS)); assertParseNotifyValue("[]", null, EnumSet.noneOf(NotifyType.class)); assertParseNotifyValue( "[ALL_COMMENTS, NEW_PATCHSETS]", null, EnumSet.of(NotifyType.ALL_COMMENTS, NotifyType.NEW_PATCHSETS)); assertParseNotifyValue("branch:master []", "branch:master", EnumSet.noneOf(NotifyType.class)); assertParseNotifyValue( "branch:master || branch:stable []", "branch:master || branch:stable", EnumSet.noneOf(NotifyType.class)); assertParseNotifyValue( "branch:master [ALL_COMMENTS]", "branch:master", EnumSet.of(NotifyType.ALL_COMMENTS)); assertParseNotifyValue( "branch:master [ALL_COMMENTS, NEW_PATCHSETS]", "branch:master", EnumSet.of(NotifyType.ALL_COMMENTS, NotifyType.NEW_PATCHSETS)); assertParseNotifyValue("* [ALL]", null, EnumSet.of(NotifyType.ALL)); assertThat(validationErrors).isEmpty(); } @Test public void parseInvalidNotifyValue() { assertParseNotifyValueFails("* [] illegal-characters-at-the-end"); assertParseNotifyValueFails("* [INVALID]"); assertParseNotifyValueFails("* [ALL_COMMENTS, UNKNOWN]"); assertParseNotifyValueFails("* [ALL_COMMENTS NEW_CHANGES]"); assertParseNotifyValueFails("* [ALL_COMMENTS, NEW_CHANGES"); assertParseNotifyValueFails("* ALL_COMMENTS, NEW_CHANGES]"); } @Test public void toNotifyValue() throws Exception { assertToNotifyValue(null, EnumSet.noneOf(NotifyType.class), "* []"); assertToNotifyValue("*", EnumSet.noneOf(NotifyType.class), "* []"); assertToNotifyValue(null, EnumSet.of(NotifyType.ALL_COMMENTS), "* [ALL_COMMENTS]"); assertToNotifyValue("branch:master", EnumSet.noneOf(NotifyType.class), "branch:master []"); assertToNotifyValue( "branch:master", EnumSet.of(NotifyType.ALL_COMMENTS, NotifyType.NEW_PATCHSETS), "branch:master [ALL_COMMENTS, NEW_PATCHSETS]"); assertToNotifyValue( "branch:master", EnumSet.of( NotifyType.ABANDONED_CHANGES, NotifyType.ALL_COMMENTS, NotifyType.NEW_CHANGES, NotifyType.NEW_PATCHSETS, NotifyType.SUBMITTED_CHANGES), "branch:master [ABANDONED_CHANGES, ALL_COMMENTS, NEW_CHANGES," + " NEW_PATCHSETS, SUBMITTED_CHANGES]"); assertToNotifyValue("*", EnumSet.of(NotifyType.ALL), "* [ALL]"); } private void assertParseNotifyValue( String notifyValue, String expectedFilter, Set<NotifyType> expectedNotifyTypes) { NotifyValue nv = parseNotifyValue(notifyValue); assertThat(nv.filter()).isEqualTo(expectedFilter); assertThat(nv.notifyTypes()).containsExactlyElementsIn(expectedNotifyTypes); } private static void assertToNotifyValue( String filter, Set<NotifyType> notifyTypes, String expectedNotifyValue) { NotifyValue nv = NotifyValue.create(filter, notifyTypes); assertThat(nv.toString()).isEqualTo(expectedNotifyValue); } private void assertParseNotifyValueFails(String notifyValue) { assertThat(validationErrors).isEmpty(); parseNotifyValue(notifyValue); assertThat(validationErrors) .named("expected validation error for notifyValue: " + notifyValue) .isNotEmpty(); validationErrors.clear(); } private NotifyValue parseNotifyValue(String notifyValue) { return NotifyValue.parse(new Account.Id(1000000), "project", notifyValue, this); } @Override public void error(ValidationError error) { validationErrors.add(error); } }