From af7905cbd7844071b0616ba27f4c422c0a77cc8d Mon Sep 17 00:00:00 2001 From: Edwin Kempin Date: Wed, 12 Jun 2013 09:44:36 +0200 Subject: [PATCH] Replace ChangeJsonTest by an acceptance test ChangeJsonTest is a unit test that verifies that change messages are correctly included in the change JSON returned by the change REST endpoints. For the setup it needs a lot of mocks. The bad thing is that this test starts failing on code changes which are unrelated to the test subject, e.g. if a new field is included into the change JSON. Fixing the test is very painful since it requires to understand the complicated mock setup and to find out which additional method calls are now done which are not yet expected by the mocks. To avoid such problems in future the test is replaced by a new acceptance test which only tests that change messages are returned correctly and that does not have any assumptions about which internal methods are invoked to provide the change messages. Change-Id: Ia008599f511602f2ac49465eb61b2dabb8b36402 Signed-off-by: Edwin Kempin --- .../acceptance/rest/change/ChangeInfo.java | 21 ++ .../rest/change/ChangeMessageInfo.java | 19 ++ .../rest/change/ChangeMessagesIT.java | 151 ++++++++++++ .../gerrit/server/change/ChangeJsonTest.java | 233 ------------------ 4 files changed, 191 insertions(+), 233 deletions(-) create mode 100644 gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeInfo.java create mode 100644 gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeMessageInfo.java create mode 100644 gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeMessagesIT.java delete mode 100644 gerrit-server/src/test/java/com/google/gerrit/server/change/ChangeJsonTest.java diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeInfo.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeInfo.java new file mode 100644 index 0000000000..4c9325e46d --- /dev/null +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeInfo.java @@ -0,0 +1,21 @@ +// Copyright (C) 2013 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.acceptance.rest.change; + +import java.util.List; + +public class ChangeInfo { + List messages; +} diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeMessageInfo.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeMessageInfo.java new file mode 100644 index 0000000000..b3c584a123 --- /dev/null +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeMessageInfo.java @@ -0,0 +1,19 @@ +// Copyright (C) 2013 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.acceptance.rest.change; + +public class ChangeMessageInfo { + String message; +} diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeMessagesIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeMessagesIT.java new file mode 100644 index 0000000000..351c320772 --- /dev/null +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/ChangeMessagesIT.java @@ -0,0 +1,151 @@ +// Copyright (C) 2013 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.acceptance.rest.change; + +import static com.google.gerrit.acceptance.git.GitUtil.cloneProject; +import static com.google.gerrit.acceptance.git.GitUtil.createProject; +import static com.google.gerrit.acceptance.git.GitUtil.initSsh; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import com.google.gerrit.acceptance.AbstractDaemonTest; +import com.google.gerrit.acceptance.AccountCreator; +import com.google.gerrit.acceptance.RestResponse; +import com.google.gerrit.acceptance.RestSession; +import com.google.gerrit.acceptance.SshSession; +import com.google.gerrit.acceptance.TestAccount; +import com.google.gerrit.acceptance.git.PushOneCommit; +import com.google.gerrit.reviewdb.client.Project; +import com.google.gerrit.reviewdb.server.ReviewDb; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.google.gwtorm.server.SchemaFactory; +import com.google.inject.Inject; + +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.util.List; + +public class ChangeMessagesIT extends AbstractDaemonTest { + + @Inject + private AccountCreator accounts; + + @Inject + private SchemaFactory reviewDbProvider; + + private TestAccount admin; + private RestSession session; + private Git git; + private ReviewDb db; + + @Before + public void setUp() throws Exception { + admin = accounts.create("admin", "admin@example.com", "Administrator", + "Administrators"); + session = new RestSession(admin); + initSsh(admin); + Project.NameKey project = new Project.NameKey("p"); + SshSession sshSession = new SshSession(admin); + createProject(sshSession, project.get()); + git = cloneProject(sshSession.getUrl() + "/" + project.get()); + sshSession.close(); + db = reviewDbProvider.open(); + } + + @After + public void cleanup() { + db.close(); + } + + @Test + public void messagesNotReturnedByDefault() throws GitAPIException, + IOException { + String changeId = createChange(); + postMessage(changeId, "Some nits need to be fixed."); + ChangeInfo c = getChange(changeId); + assertNull(c.messages); + } + + @Test + public void noMessages() throws GitAPIException, + IOException { + String changeId = createChange(); + ChangeInfo c = getChangeWithMessages(changeId); + assertNotNull(c.messages); + assertTrue(c.messages.isEmpty()); + } + + @Test + public void messagesReturnedInChronologicalOrder() throws GitAPIException, + IOException { + String changeId = createChange(); + String firstMessage = "Some nits need to be fixed."; + postMessage(changeId, firstMessage); + String secondMessage = "I like this feature."; + postMessage(changeId, secondMessage); + ChangeInfo c = getChangeWithMessages(changeId); + assertNotNull(c.messages); + assertEquals(2, c.messages.size()); + assertMessage(firstMessage, c.messages.get(0).message); + assertMessage(secondMessage, c.messages.get(1).message); + } + + private String createChange() throws GitAPIException, + IOException { + PushOneCommit push = new PushOneCommit(db, admin.getIdent()); + return push.to(git, "refs/for/master").getChangeId(); + } + + private ChangeInfo getChange(String changeId) throws IOException { + return getChange(changeId, false); + } + + private ChangeInfo getChangeWithMessages(String changeId) throws IOException { + return getChange(changeId, true); + } + + private ChangeInfo getChange(String changeId, boolean includeMessages) + throws IOException { + RestResponse r = + session.get("/changes/?q=" + changeId + + (includeMessages ? "&o=MESSAGES" : "")); + List c = (new Gson()).fromJson(r.getReader(), + new TypeToken>() {}.getType()); + return c.get(0); + } + + private void assertMessage(String expected, String actual) { + assertEquals("Patch Set 1:\n\n" + expected, actual); + } + + private void postMessage(String changeId, String msg) throws IOException { + ReviewInput in = new ReviewInput(); + in.message = msg; + session.post("/changes/" + changeId + "/revisions/1/review", in).consume(); + } + + @SuppressWarnings("unused") + private class ReviewInput { + String message; + } +} diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/change/ChangeJsonTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/change/ChangeJsonTest.java deleted file mode 100644 index 14e0ebf242..0000000000 --- a/gerrit-server/src/test/java/com/google/gerrit/server/change/ChangeJsonTest.java +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright (C) 2013 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.change; - -import static org.easymock.EasyMock.anyBoolean; -import static org.easymock.EasyMock.anyObject; -import static org.easymock.EasyMock.createMock; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.expectLastCall; -import static org.easymock.EasyMock.replay; - -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import com.google.gerrit.common.changes.ListChangesOption; -import com.google.gerrit.reviewdb.client.Account; -import com.google.gerrit.reviewdb.client.Branch; -import com.google.gerrit.reviewdb.client.Change; -import com.google.gerrit.reviewdb.client.ChangeMessage; -import com.google.gerrit.reviewdb.client.PatchSet; -import com.google.gerrit.reviewdb.client.PatchSetApproval; -import com.google.gerrit.reviewdb.client.Project; -import com.google.gerrit.reviewdb.server.ChangeAccess; -import com.google.gerrit.reviewdb.server.ChangeMessageAccess; -import com.google.gerrit.reviewdb.server.PatchSetAccess; -import com.google.gerrit.reviewdb.server.PatchSetApprovalAccess; -import com.google.gerrit.reviewdb.server.ReviewDb; -import com.google.gerrit.server.CurrentUser; -import com.google.gerrit.server.account.AccountByEmailCache; -import com.google.gerrit.server.account.AccountCache; -import com.google.gerrit.server.account.AccountInfo; -import com.google.gerrit.server.account.CapabilityControl; -import com.google.gerrit.server.account.GroupBackend; -import com.google.gerrit.server.account.Realm; -import com.google.gerrit.server.change.ChangeJson.ChangeInfo; -import com.google.gerrit.server.change.ChangeJson.ChangeMessageInfo; -import com.google.gerrit.server.config.AnonymousCowardName; -import com.google.gerrit.server.config.CanonicalWebUrl; -import com.google.gerrit.server.config.GerritServerConfig; -import com.google.gerrit.server.git.GitRepositoryManager; -import com.google.gerrit.server.patch.PatchListCache; -import com.google.gerrit.server.project.ProjectCache; -import com.google.gerrit.server.query.change.ChangeData; -import com.google.gwtorm.server.ListResultSet; -import com.google.gwtorm.server.OrmException; -import com.google.gwtorm.server.ResultSet; -import com.google.inject.Binder; -import com.google.inject.Guice; -import com.google.inject.Module; - -import junit.framework.TestCase; - -import org.easymock.EasyMock; -import org.easymock.IAnswer; -import org.eclipse.jgit.lib.Config; - -import java.sql.Timestamp; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -public class ChangeJsonTest extends TestCase { - - public void testFormatChangeMessages() throws OrmException { - - // create mocks - final CurrentUser currentUser = createMock(CurrentUser.class); - final GitRepositoryManager grm = createMock(GitRepositoryManager.class); - final AccountByEmailCache abec = createMock(AccountByEmailCache.class); - final AccountCache ac = createMock(AccountCache.class); - final AccountInfo.Loader.Factory alf = - createMock(AccountInfo.Loader.Factory.class); - final CapabilityControl.Factory ccf = - createMock(CapabilityControl.Factory.class); - final GroupBackend gb = createMock(GroupBackend.class); - final Realm r = createMock(Realm.class); - final PatchListCache plc = createMock(PatchListCache.class); - final ProjectCache pc = createMock(ProjectCache.class); - final Config config = new Config(); // unable to mock - final ReviewDb rdb = createMock(ReviewDb.class); - final ChangeAccess ca = createMock(ChangeAccess.class); - final PatchSetAccess psa = createMock(PatchSetAccess.class); - final PatchSetApprovalAccess psaa = - createMock(PatchSetApprovalAccess.class); - final ChangeMessageAccess cma = createMock(ChangeMessageAccess.class); - AccountInfo.Loader accountLoader = createMock(AccountInfo.Loader.class); - - // create ChangeJson instance - Module mod = new Module() { - @Override - public void configure(Binder binder) { - binder.bind(CurrentUser.class).toInstance(currentUser); - binder.bind(GitRepositoryManager.class).toInstance(grm); - binder.bind(AccountByEmailCache.class).toInstance(abec); - binder.bind(AccountCache.class).toInstance(ac); - binder.bind(AccountInfo.Loader.Factory.class).toInstance(alf); - binder.bind(CapabilityControl.Factory.class).toInstance(ccf); - binder.bind(GroupBackend.class).toInstance(gb); - binder.bind(Realm.class).toInstance(r); - binder.bind(PatchListCache.class).toInstance(plc); - binder.bind(ProjectCache.class).toInstance(pc); - binder.bind(ReviewDb.class).toInstance(rdb); - binder.bind(Config.class).annotatedWith(GerritServerConfig.class) - .toInstance(config); - binder.bind(String.class).annotatedWith(CanonicalWebUrl.class) - .toInstance(""); - binder.bind(String.class).annotatedWith(AnonymousCowardName.class) - .toInstance(""); - } - }; - ChangeJson json = Guice.createInjector(mod).getInstance(ChangeJson.class); - - // define mock behavior for tests - expect(alf.create(anyBoolean())).andReturn(accountLoader).anyTimes(); - - Project.NameKey proj = new Project.NameKey("ProjectNameKey"); - Branch.NameKey forBranch = new Branch.NameKey(proj, "BranchNameKey"); - - Change.Key changeKey123 = new Change.Key("ChangeKey123"); - Change.Id changeId123 = new Change.Id(123); - Change change123 = new Change(changeKey123, changeId123, null, forBranch); - - Change.Key changeKey234 = new Change.Key("ChangeKey234"); - Change.Id changeId234 = new Change.Id(234); - Change change234 = new Change(changeKey234, changeId234, null, forBranch); - - expect(ca.get(Sets.newHashSet(changeId123))) - .andAnswer(results(Change.class, change123)).anyTimes(); - expect(ca.get(changeId123)).andReturn(change123).anyTimes(); - expect(ca.get(Sets.newHashSet(changeId234))) - .andAnswer(results(Change.class, change234)); - expect(ca.get(changeId234)).andReturn(change234); - expect(rdb.changes()).andReturn(ca).anyTimes(); - - expect(psa.get(EasyMock.>anyObject())) - .andAnswer(results(PatchSet.class)).anyTimes(); - expect(rdb.patchSets()).andReturn(psa).anyTimes(); - - expect(psaa.byPatchSet(anyObject(PatchSet.Id.class))) - .andAnswer(results(PatchSetApproval.class)).anyTimes(); - expect(rdb.patchSetApprovals()).andReturn(psaa).anyTimes(); - - expect(currentUser.getStarredChanges()) - .andReturn(Collections.emptySet()).anyTimes(); - - long timeBase = System.currentTimeMillis(); - ChangeMessage changeMessage1 =changeMessage( - changeId123, "cm1", 111, timeBase, 1111, "first message"); - ChangeMessage changeMessage2 = changeMessage( - changeId123, "cm2", 222, timeBase + 1000, 1111, "second message"); - expect(cma.byChange(changeId123)) - .andAnswer(results(ChangeMessage.class, changeMessage2, changeMessage1)) - .anyTimes(); - expect(cma.byChange(changeId234)).andAnswer(results(ChangeMessage.class)); - expect(rdb.changeMessages()).andReturn(cma).anyTimes(); - - expect(accountLoader.get(anyObject(Account.Id.class))) - .andAnswer(accountForId()).anyTimes(); - accountLoader.fill(); - expectLastCall().anyTimes(); - - replay(rdb, ca, psa, psaa, alf, currentUser, cma, accountLoader); - - // test 1: messages not returned by default - ChangeInfo ci = json.format(new ChangeData(changeId123)); - assertNull(ci.messages); - - json.addOption(ListChangesOption.MESSAGES); - - // test 2: two change messages, in chronological order - ci = json.format(new ChangeData(changeId123)); - assertNotNull(ci.messages); - assertEquals(2, ci.messages.size()); - Iterator cmis = ci.messages.iterator(); - assertEquals(changeMessage1, cmis.next()); - assertEquals(changeMessage2, cmis.next()); - - // test 3: no change messages - ci = json.format(new ChangeData(changeId234)); - assertNotNull(ci.messages); - assertEquals(0, ci.messages.size()); - } - - private static IAnswer accountForId() { - return new IAnswer() { - @Override - public AccountInfo answer() throws Throwable { - Account.Id id = (Account.Id) EasyMock.getCurrentArguments()[0]; - AccountInfo ai = new AccountInfo(id); - return ai; - }}; - } - - private static IAnswer> results(Class type, T... items) { - final List list = Lists.newArrayList(items); - return new IAnswer>() { - @Override - public ResultSet answer() throws Throwable { - return new ListResultSet(list); - }}; - } - - private static void assertEquals(ChangeMessage cm, ChangeMessageInfo cmi) { - assertEquals(cm.getPatchSetId().get(), (int) cmi._revisionNumber); - assertEquals(cm.getMessage(), cmi.message); - assertEquals(cm.getKey().get(), cmi.id); - assertEquals(cm.getWrittenOn(), cmi.date); - assertNotNull(cmi.author); - assertEquals(cm.getAuthor(), cmi.author._id); - } - - private static ChangeMessage changeMessage(Change.Id changeId, - String uuid, int accountId, long time, int psId, String message) { - ChangeMessage.Key key = new ChangeMessage.Key(changeId, uuid); - Account.Id author = new Account.Id(accountId); - Timestamp updated = new Timestamp(time); - PatchSet.Id ps = new PatchSet.Id(changeId, psId); - ChangeMessage changeMessage = new ChangeMessage(key, author, updated, ps); - changeMessage.setMessage(message); - return changeMessage; - } -}