Implement extracting properties from events Change-Id: I98ad49f935902edc89ab051c3389ef336aaa4c6e
diff --git a/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/util/PropertyAttributeExtractor.java b/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/util/PropertyAttributeExtractor.java new file mode 100644 index 0000000..539b646 --- /dev/null +++ b/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/util/PropertyAttributeExtractor.java
@@ -0,0 +1,101 @@ +//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.googlesource.gerrit.plugins.hooks.util; + +import java.util.Set; + +import com.google.common.collect.Sets; +import com.google.gerrit.server.data.AccountAttribute; +import com.google.gerrit.server.data.ChangeAttribute; +import com.google.gerrit.server.data.PatchSetAttribute; +import com.google.gerrit.server.data.RefUpdateAttribute; +import com.google.inject.Inject; + +import com.googlesource.gerrit.plugins.hooks.workflow.Property; + +/** + * Extractor to translate the various {@code *Attribute}s to + * {@link Property Properties}. + */ +public class PropertyAttributeExtractor { + private Property.Factory propertyFactory; + + @Inject + PropertyAttributeExtractor(Property.Factory propertyFactory) { + this.propertyFactory = propertyFactory; + } + + public Set<Property> extractFrom(AccountAttribute accountAttribute, + String prefix) { + Set<Property> properties = Sets.newHashSet(); + if (accountAttribute != null) { + properties.add(propertyFactory.create(prefix + "-email", + accountAttribute.email)); + properties.add(propertyFactory.create(prefix + "-username", + accountAttribute.username)); + properties.add(propertyFactory.create(prefix + "-name", + accountAttribute.name)); + } + return properties; + } + + public Set<Property> extractFrom(ChangeAttribute changeAttribute) { + Set<Property> properties = Sets.newHashSet(); + properties.add(propertyFactory.create("project", changeAttribute.project)); + properties.add(propertyFactory.create("branch", changeAttribute.branch)); + properties.add(propertyFactory.create("topic", changeAttribute.topic)); + properties.add(propertyFactory.create("subject", changeAttribute.subject)); + properties.add(propertyFactory.create("change-id", changeAttribute.id)); + properties.add(propertyFactory.create("change-number", changeAttribute.number)); + properties.add(propertyFactory.create("change-url", changeAttribute.url)); + properties.addAll(extractFrom(changeAttribute.owner, "owner")); + return properties; + } + + public Set<Property>extractFrom(PatchSetAttribute patchSetAttribute) { + Set<Property> properties = Sets.newHashSet(); + properties.add(propertyFactory.create("revision", + patchSetAttribute.revision)); + properties.add(propertyFactory.create("patch-set-number", + patchSetAttribute.number)); + properties.add(propertyFactory.create("ref", patchSetAttribute.ref)); + properties.add(propertyFactory.create("created-on", + patchSetAttribute.createdOn.toString())); + properties.add(propertyFactory.create("parents", + patchSetAttribute.parents.toString())); + properties.add(propertyFactory.create("deletions", + Integer.toString(patchSetAttribute.sizeDeletions))); + properties.add(propertyFactory.create("insertions", + Integer.toString(patchSetAttribute.sizeInsertions))); + properties.addAll(extractFrom(patchSetAttribute.uploader, + "uploader")); + properties.addAll(extractFrom(patchSetAttribute.author, + "author")); + return properties; + } + + public Set<Property>extractFrom(RefUpdateAttribute refUpdateAttribute) { + Set<Property> properties = Sets.newHashSet(); + properties.add(propertyFactory.create("revision", + refUpdateAttribute.newRev)); + properties.add(propertyFactory.create("revision-old", + refUpdateAttribute.oldRev)); + properties.add(propertyFactory.create("project", + refUpdateAttribute.project)); + properties.add(propertyFactory.create("ref", + refUpdateAttribute.refName)); + return properties; + } +}
diff --git a/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/util/PropertyExtractor.java b/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/util/PropertyExtractor.java index 9cf514e..895ec33 100644 --- a/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/util/PropertyExtractor.java +++ b/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/util/PropertyExtractor.java
@@ -14,9 +14,18 @@ package com.googlesource.gerrit.plugins.hooks.util; +import java.util.Map; import java.util.Set; +import com.google.common.collect.Sets; +import com.google.gerrit.server.events.ChangeAbandonedEvent; import com.google.gerrit.server.events.ChangeEvent; +import com.google.gerrit.server.events.ChangeMergedEvent; +import com.google.gerrit.server.events.ChangeRestoredEvent; +import com.google.gerrit.server.events.CommentAddedEvent; +import com.google.gerrit.server.events.PatchSetCreatedEvent; +import com.google.gerrit.server.events.RefUpdatedEvent; +import com.google.inject.Inject; import com.googlesource.gerrit.plugins.hooks.workflow.Property; @@ -25,14 +34,89 @@ * {@link Property Properties}. */ public class PropertyExtractor { + private IssueExtractor issueExtractor; + private Property.Factory propertyFactory; + private PropertyAttributeExtractor propertyAttributeExtractor; + + @Inject + PropertyExtractor(IssueExtractor issueExtractor, + Property.Factory propertyFactory, + PropertyAttributeExtractor propertyAttributeExtractor) { + this.issueExtractor = issueExtractor; + this.propertyFactory = propertyFactory; + this.propertyAttributeExtractor = propertyAttributeExtractor; + } + + private Map<String,Set<String>> extractFrom(ChangeAbandonedEvent event, + Set<Property> common) { + common.add(propertyFactory.create("event-type", event.type)); + common.addAll(propertyAttributeExtractor.extractFrom(event.change)); + common.addAll(propertyAttributeExtractor.extractFrom(event.abandoner, "abandoner")); + common.addAll(propertyAttributeExtractor.extractFrom(event.patchSet)); + common.add(propertyFactory.create("reason", event.reason)); + return issueExtractor.getIssueIds(event.change.project, + event.patchSet.revision); + } + + private Map<String,Set<String>> extractFrom(ChangeMergedEvent event, + Set<Property> common) { + common.add(propertyFactory.create("event-type", event.type)); + common.addAll(propertyAttributeExtractor.extractFrom(event.change)); + common.addAll(propertyAttributeExtractor.extractFrom(event.submitter, "submitter")); + common.addAll(propertyAttributeExtractor.extractFrom(event.patchSet)); + return issueExtractor.getIssueIds(event.change.project, + event.patchSet.revision); + } + + private Map<String,Set<String>> extractFrom(ChangeRestoredEvent event, + Set<Property> common) { + common.add(propertyFactory.create("event-type", event.type)); + common.addAll(propertyAttributeExtractor.extractFrom(event.change)); + common.addAll(propertyAttributeExtractor.extractFrom(event.restorer, "restorer")); + common.addAll(propertyAttributeExtractor.extractFrom(event.patchSet)); + common.add(propertyFactory.create("reason", event.reason)); + return issueExtractor.getIssueIds(event.change.project, + event.patchSet.revision); + } + + private Map<String,Set<String>> extractFrom(RefUpdatedEvent event, + Set<Property> common) { + common.add(propertyFactory.create("event-type", event.type)); + common.addAll(propertyAttributeExtractor.extractFrom(event.submitter, "submitter")); + common.addAll(propertyAttributeExtractor.extractFrom(event.refUpdate)); + return issueExtractor.getIssueIds(event.refUpdate.project, + event.refUpdate.newRev); + } + + private Map<String,Set<String>> extractFrom(PatchSetCreatedEvent event, + Set<Property> common) { + common.add(propertyFactory.create("event-type", event.type)); + common.addAll(propertyAttributeExtractor.extractFrom(event.change)); + common.addAll(propertyAttributeExtractor.extractFrom(event.patchSet)); + common.addAll(propertyAttributeExtractor.extractFrom(event.uploader, "uploader")); + return issueExtractor.getIssueIds(event.change.project, + event.patchSet.revision); + } + + private Map<String,Set<String>> extractFrom(CommentAddedEvent event, + Set<Property> common) { + common.add(propertyFactory.create("event-type", event.type)); + common.addAll(propertyAttributeExtractor.extractFrom(event.change)); + common.addAll(propertyAttributeExtractor.extractFrom(event.patchSet)); + common.addAll(propertyAttributeExtractor.extractFrom(event.author, "commenter")); + common.add(propertyFactory.create("comment", event.comment)); + //TODO approvals + return issueExtractor.getIssueIds(event.change.project, + event.patchSet.revision); + } + /** * A set of property sets extracted from an event. * * As events may relate to more that a single issue, and properties sets are - * should be tied to a single issue, returning {@code Collection<Property>} - * is not sufficient, and we need to return - * {@code Collection<Collection<Property>>}. Using this approach, a - * PatchSetCreatedEvent for a patch set with commit message: + * should be tied to a single issue, returning {@code Set<Property>} is not + * sufficient, and we need to return {@code Set<Set<Property>>}. Using this + * approach, a PatchSetCreatedEvent for a patch set with commit message: * * <pre> * (bug 4711) Fix treatment of special characters in title @@ -47,7 +131,7 @@ * <pre> * issue: 4711 * association: subject - * event: PatchSetCreatedEvent + * event: patchset-created * </pre> * * and @@ -55,11 +139,11 @@ * <pre> * issue: 42 * association: body - * event: PatchSetCreatedEvent + * event: patchset-created * </pre> * - * Thereby, sites can choose to to cause different actions for different - * issues associated to the same event. So in the above example, a comment + * Thereby, sites can choose to cause different actions for different issues + * associated to the same event. So in the above example, a comment * "mentioned in change 123" may be added for issue 42, and a comment * "fixed by change 123” may be added for issue 4711. * @@ -67,7 +151,39 @@ * @return sets of property sets extracted from the event. */ public Set<Set<Property>> extractFrom(ChangeEvent event) { - // TODO implement - throw new RuntimeException("unimplemented"); + Map<String,Set<String>> associations = null; + Set<Set<Property>> ret = Sets.newHashSet(); + + Set<Property> common = Sets.newHashSet(); + common.add(propertyFactory.create("event", event.getClass().getName())); + + if (event instanceof ChangeAbandonedEvent) { + associations = extractFrom((ChangeAbandonedEvent) event, common); + } else if (event instanceof ChangeMergedEvent) { + associations = extractFrom((ChangeMergedEvent) event, common); + } else if (event instanceof ChangeRestoredEvent) { + associations = extractFrom((ChangeRestoredEvent) event, common); + } else if (event instanceof CommentAddedEvent) { + associations = extractFrom((CommentAddedEvent) event, common); + } else if (event instanceof PatchSetCreatedEvent) { + associations = extractFrom((PatchSetCreatedEvent) event, common); + } else if (event instanceof RefUpdatedEvent) { + associations = extractFrom((RefUpdatedEvent) event, common); + } + + if (associations != null) { + for (String issue : associations.keySet()) { + Set<Property> properties = Sets.newHashSet(); + Property property = propertyFactory.create("issue", issue); + properties.add(property); + for (String occurrence: associations.get(issue)) { + property = propertyFactory.create("association", occurrence); + properties.add(property); + } + properties.addAll(common); + ret.add(properties); + } + } + return ret; } }
diff --git a/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/util/PropertyAttributeExtractorTest.java b/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/util/PropertyAttributeExtractorTest.java new file mode 100644 index 0000000..0aa5da5 --- /dev/null +++ b/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/util/PropertyAttributeExtractorTest.java
@@ -0,0 +1,311 @@ +// 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.googlesource.gerrit.plugins.hooks.util; + +import static org.easymock.EasyMock.expect; + +import java.util.Set; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.google.gerrit.server.config.FactoryModule; +import com.google.gerrit.server.data.AccountAttribute; +import com.google.gerrit.server.data.ChangeAttribute; +import com.google.gerrit.server.data.PatchSetAttribute; +import com.google.gerrit.server.data.RefUpdateAttribute; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.googlesource.gerrit.plugins.hooks.testutil.LoggingMockingTestCase; +import com.googlesource.gerrit.plugins.hooks.workflow.Property; + +public class PropertyAttributeExtractorTest extends LoggingMockingTestCase { + private Injector injector; + + private Property.Factory propertyFactory; + + public void testAccountAttributeNull() { + replayMocks(); + + PropertyAttributeExtractor extractor = + injector.getInstance(PropertyAttributeExtractor.class); + + Set<Property> actual = extractor.extractFrom(null, "prefix"); + + Set<Property> expected = Sets.newHashSet(); + + assertEquals("Properties do not match", expected, actual); + } + + public void testAccountAttribute() { + AccountAttribute accountAttribute = new AccountAttribute(); + accountAttribute.email = "testEmail"; + accountAttribute.name = "testName"; + accountAttribute.username = "testUsername"; + + Property propertyEmail= createMock(Property.class); + expect(propertyFactory.create("prefix-email", "testEmail")) + .andReturn(propertyEmail); + + Property propertyName = createMock(Property.class); + expect(propertyFactory.create("prefix-name", "testName")) + .andReturn(propertyName); + + Property propertyUsername = createMock(Property.class); + expect(propertyFactory.create("prefix-username", "testUsername")) + .andReturn(propertyUsername); + + replayMocks(); + + PropertyAttributeExtractor extractor = + injector.getInstance(PropertyAttributeExtractor.class); + + Set<Property> actual = extractor.extractFrom(accountAttribute, "prefix"); + + Set<Property> expected = Sets.newHashSet(); + expected.add(propertyEmail); + expected.add(propertyName); + expected.add(propertyUsername); + assertEquals("Properties do not match", expected, actual); + } + + public void testChangeAttribute() { + AccountAttribute owner = new AccountAttribute(); + owner.email = "testEmail"; + owner.name = "testName"; + owner.username = "testUsername"; + + ChangeAttribute changeAttribute = new ChangeAttribute(); + changeAttribute.project = "testProject"; + changeAttribute.branch = "testBranch"; + changeAttribute.topic = "testTopic"; + changeAttribute.subject = "testSubject"; + changeAttribute.id = "testId"; + changeAttribute.number = "4711"; + changeAttribute.url = "http://www.example.org/test"; + changeAttribute.owner = owner; + + Property propertyProject = createMock(Property.class); + expect(propertyFactory.create("project", "testProject")) + .andReturn(propertyProject); + + Property propertyBranch = createMock(Property.class); + expect(propertyFactory.create("branch", "testBranch")) + .andReturn(propertyBranch); + + Property propertyTopic = createMock(Property.class); + expect(propertyFactory.create("topic", "testTopic")) + .andReturn(propertyTopic); + + Property propertySubject = createMock(Property.class); + expect(propertyFactory.create("subject", "testSubject")) + .andReturn(propertySubject); + + Property propertyId = createMock(Property.class); + expect(propertyFactory.create("change-id", "testId")) + .andReturn(propertyId); + + Property propertyNumber = createMock(Property.class); + expect(propertyFactory.create("change-number", "4711")) + .andReturn(propertyNumber); + + Property propertyUrl = createMock(Property.class); + expect(propertyFactory.create("change-url", "http://www.example.org/test")) + .andReturn(propertyUrl); + + Property propertyEmail= createMock(Property.class); + expect(propertyFactory.create("owner-email", "testEmail")) + .andReturn(propertyEmail); + + Property propertyName = createMock(Property.class); + expect(propertyFactory.create("owner-name", "testName")) + .andReturn(propertyName); + + Property propertyUsername = createMock(Property.class); + expect(propertyFactory.create("owner-username", "testUsername")) + .andReturn(propertyUsername); + + + replayMocks(); + + PropertyAttributeExtractor extractor = + injector.getInstance(PropertyAttributeExtractor.class); + + Set<Property> actual = extractor.extractFrom(changeAttribute); + + Set<Property> expected = Sets.newHashSet(); + expected.add(propertyProject); + expected.add(propertyBranch); + expected.add(propertyTopic); + expected.add(propertySubject); + expected.add(propertyId); + expected.add(propertyNumber); + expected.add(propertyUrl); + expected.add(propertyEmail); + expected.add(propertyName); + expected.add(propertyUsername); + assertEquals("Properties do not match", expected, actual); + } + + public void testPatchSetAttribute() { + AccountAttribute uploader = new AccountAttribute(); + uploader.email = "testEmail1"; + uploader.name = "testName1"; + uploader.username = "testUsername1"; + + AccountAttribute author = new AccountAttribute(); + author.email = "testEmail2"; + author.name = "testName2"; + author.username = "testUsername2"; + + PatchSetAttribute patchSetAttribute = new PatchSetAttribute(); + patchSetAttribute.revision = "1234567891123456789212345678931234567894"; + patchSetAttribute.number = "42"; + patchSetAttribute.ref = "testRef"; + patchSetAttribute.createdOn = 1234567890L; + patchSetAttribute.parents = Lists.newArrayList("parent1", "parent2"); + patchSetAttribute.sizeDeletions = 7; + patchSetAttribute.sizeInsertions = 12; + patchSetAttribute.uploader = uploader; + patchSetAttribute.author = author; + + Property propertyRevision = createMock(Property.class); + expect(propertyFactory.create("revision", + "1234567891123456789212345678931234567894")) + .andReturn(propertyRevision); + + Property propertyNumber = createMock(Property.class); + expect(propertyFactory.create("patch-set-number", "42")) + .andReturn(propertyNumber); + + Property propertyRef = createMock(Property.class); + expect(propertyFactory.create("ref", "testRef")) + .andReturn(propertyRef); + + Property propertyCreatedOn = createMock(Property.class); + expect(propertyFactory.create("created-on", "1234567890")) + .andReturn(propertyCreatedOn); + + Property propertyParents = createMock(Property.class); + expect(propertyFactory.create("parents", "[parent1, parent2]")) + .andReturn(propertyParents); + + Property propertyDeletions = createMock(Property.class); + expect(propertyFactory.create("deletions", "7")) + .andReturn(propertyDeletions); + + Property propertyInsertions = createMock(Property.class); + expect(propertyFactory.create("insertions", "12")) + .andReturn(propertyInsertions); + + Property propertyEmail1 = createMock(Property.class); + expect(propertyFactory.create("uploader-email", "testEmail1")) + .andReturn(propertyEmail1); + + Property propertyName1 = createMock(Property.class); + expect(propertyFactory.create("uploader-name", "testName1")) + .andReturn(propertyName1); + + Property propertyUsername1 = createMock(Property.class); + expect(propertyFactory.create("uploader-username", "testUsername1")) + .andReturn(propertyUsername1); + + Property propertyEmail2 = createMock(Property.class); + expect(propertyFactory.create("author-email", "testEmail2")) + .andReturn(propertyEmail2); + + Property propertyName2 = createMock(Property.class); + expect(propertyFactory.create("author-name", "testName2")) + .andReturn(propertyName2); + + Property propertyUsername2 = createMock(Property.class); + expect(propertyFactory.create("author-username", "testUsername2")) + .andReturn(propertyUsername2); + + replayMocks(); + + PropertyAttributeExtractor extractor = + injector.getInstance(PropertyAttributeExtractor.class); + + Set<Property> actual = extractor.extractFrom(patchSetAttribute); + + Set<Property> expected = Sets.newHashSet(); + expected.add(propertyRevision); + expected.add(propertyNumber); + expected.add(propertyRef); + expected.add(propertyCreatedOn); + expected.add(propertyParents); + expected.add(propertyDeletions); + expected.add(propertyInsertions); + expected.add(propertyEmail1); + expected.add(propertyName1); + expected.add(propertyUsername1); + expected.add(propertyEmail2); + expected.add(propertyName2); + expected.add(propertyUsername2); + assertEquals("Properties do not match", expected, actual); + } + + public void testRefUpdateAttribute() { + RefUpdateAttribute refUpdateAttribute = new RefUpdateAttribute(); + refUpdateAttribute.newRev = "1234567891123456789212345678931234567894"; + refUpdateAttribute.oldRev = "9876543211987654321298765432139876543214"; + refUpdateAttribute.project = "testProject"; + refUpdateAttribute.refName = "testRef"; + + Property propertyRevision = createMock(Property.class); + expect(propertyFactory.create("revision", + "1234567891123456789212345678931234567894")) + .andReturn(propertyRevision); + + Property propertyRevisionOld = createMock(Property.class); + expect(propertyFactory.create("revision-old", + "9876543211987654321298765432139876543214")) + .andReturn(propertyRevisionOld); + + Property propertyProject = createMock(Property.class); + expect(propertyFactory.create("project", "testProject")) + .andReturn(propertyProject); + + Property propertyRef = createMock(Property.class); + expect(propertyFactory.create("ref", "testRef")) + .andReturn(propertyRef); + + replayMocks(); + + PropertyAttributeExtractor extractor = + injector.getInstance(PropertyAttributeExtractor.class); + + Set<Property> actual = extractor.extractFrom(refUpdateAttribute); + + Set<Property> expected = Sets.newHashSet(); + expected.add(propertyRevision); + expected.add(propertyRevisionOld); + expected.add(propertyProject); + expected.add(propertyRef); + assertEquals("Properties do not match", expected, actual); + } + + public void setUp() throws Exception { + super.setUp(); + injector = Guice.createInjector(new TestModule()); + } + + private class TestModule extends FactoryModule { + @Override + protected void configure() { + propertyFactory = createMock(Property.Factory.class); + bind(Property.Factory.class).toInstance(propertyFactory); + } + } +} \ No newline at end of file
diff --git a/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/util/PropertyExtractorTest.java b/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/util/PropertyExtractorTest.java new file mode 100644 index 0000000..ef9270b --- /dev/null +++ b/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/util/PropertyExtractorTest.java
@@ -0,0 +1,358 @@ +// 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.googlesource.gerrit.plugins.hooks.util; + +import static org.easymock.EasyMock.expect; + +import java.util.HashMap; +import java.util.Set; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.google.gerrit.server.config.FactoryModule; +import com.google.gerrit.server.data.AccountAttribute; +import com.google.gerrit.server.data.ChangeAttribute; +import com.google.gerrit.server.data.PatchSetAttribute; +import com.google.gerrit.server.data.RefUpdateAttribute; +import com.google.gerrit.server.events.ChangeAbandonedEvent; +import com.google.gerrit.server.events.ChangeEvent; +import com.google.gerrit.server.events.ChangeMergedEvent; +import com.google.gerrit.server.events.ChangeRestoredEvent; +import com.google.gerrit.server.events.CommentAddedEvent; +import com.google.gerrit.server.events.PatchSetCreatedEvent; +import com.google.gerrit.server.events.RefUpdatedEvent; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.googlesource.gerrit.plugins.hooks.testutil.LoggingMockingTestCase; +import com.googlesource.gerrit.plugins.hooks.util.IssueExtractor; +import com.googlesource.gerrit.plugins.hooks.util.PropertyExtractor; +import com.googlesource.gerrit.plugins.hooks.workflow.Property; + +public class PropertyExtractorTest extends LoggingMockingTestCase { + private Injector injector; + + private IssueExtractor issueExtractor; + private Property.Factory propertyFactory; + private PropertyAttributeExtractor propertyAttributeExtractor; + + public void testDummyChangeEvent() { + PropertyExtractor propertyExtractor = injector.getInstance( + PropertyExtractor.class); + + Property property1 = createMock(Property.class); + expect(propertyFactory.create("event", "com.googlesource.gerrit.plugins." + + "hooks.util.PropertyExtractorTest$DummyChangeEvent")) + .andReturn(property1); + + replayMocks(); + + Set<Set<Property>> actual = propertyExtractor.extractFrom( + new DummyChangeEvent()); + + Set<Set<Property>> expected = Sets.newHashSet(); + assertEquals("Properties do not match", expected, actual); + } + + public void testChangeAbandonedEvent() { + ChangeAbandonedEvent event = new ChangeAbandonedEvent(); + + ChangeAttribute changeAttribute = createMock(ChangeAttribute.class); + event.change = changeAttribute; + Property propertyChange = createMock(Property.class); + expect(propertyAttributeExtractor.extractFrom(changeAttribute)) + .andReturn(Sets.newHashSet(propertyChange)); + + AccountAttribute accountAttribute = createMock(AccountAttribute.class); + event.abandoner= accountAttribute; + Property propertySubmitter = createMock(Property.class); + expect(propertyAttributeExtractor.extractFrom(accountAttribute, + "abandoner")).andReturn(Sets.newHashSet(propertySubmitter)); + + PatchSetAttribute patchSetAttribute = createMock(PatchSetAttribute.class); + event.patchSet = patchSetAttribute; + Property propertyPatchSet = createMock(Property.class); + expect(propertyAttributeExtractor.extractFrom(patchSetAttribute)) + .andReturn(Sets.newHashSet(propertyPatchSet)); + + event.reason = "testReason"; + Property propertyReason = createMock(Property.class); + expect(propertyFactory.create("reason", "testReason")) + .andReturn(propertyReason); + + changeAttribute.project = "testProject"; + patchSetAttribute.revision = "testRevision"; + + Set<Property> common = Sets.newHashSet(); + common.add(propertyChange); + common.add(propertySubmitter); + common.add(propertyPatchSet); + common.add(propertyReason); + + eventHelper(event, "ChangeAbandonedEvent", "change-abandoned", common); + } + + public void testChangeMergedEvent() { + ChangeMergedEvent event = new ChangeMergedEvent(); + + ChangeAttribute changeAttribute = createMock(ChangeAttribute.class); + event.change = changeAttribute; + Property propertyChange = createMock(Property.class); + expect(propertyAttributeExtractor.extractFrom(changeAttribute)) + .andReturn(Sets.newHashSet(propertyChange)); + + AccountAttribute accountAttribute = createMock(AccountAttribute.class); + event.submitter = accountAttribute; + Property propertySubmitter = createMock(Property.class); + expect(propertyAttributeExtractor.extractFrom(accountAttribute, + "submitter")).andReturn(Sets.newHashSet(propertySubmitter)); + + PatchSetAttribute patchSetAttribute = createMock(PatchSetAttribute.class); + event.patchSet = patchSetAttribute; + Property propertyPatchSet = createMock(Property.class); + expect(propertyAttributeExtractor.extractFrom(patchSetAttribute)) + .andReturn(Sets.newHashSet(propertyPatchSet)); + + changeAttribute.project = "testProject"; + patchSetAttribute.revision = "testRevision"; + + Set<Property> common = Sets.newHashSet(); + common.add(propertyChange); + common.add(propertySubmitter); + common.add(propertyPatchSet); + + eventHelper(event, "ChangeMergedEvent", "change-merged", common); + } + + public void testChangeRestoredEvent() { + ChangeRestoredEvent event = new ChangeRestoredEvent(); + + ChangeAttribute changeAttribute = createMock(ChangeAttribute.class); + event.change = changeAttribute; + Property propertyChange = createMock(Property.class); + expect(propertyAttributeExtractor.extractFrom(changeAttribute)) + .andReturn(Sets.newHashSet(propertyChange)); + + AccountAttribute accountAttribute = createMock(AccountAttribute.class); + event.restorer = accountAttribute; + Property propertySubmitter = createMock(Property.class); + expect(propertyAttributeExtractor.extractFrom(accountAttribute, + "restorer")).andReturn(Sets.newHashSet(propertySubmitter)); + + PatchSetAttribute patchSetAttribute = createMock(PatchSetAttribute.class); + event.patchSet = patchSetAttribute; + Property propertyPatchSet = createMock(Property.class); + expect(propertyAttributeExtractor.extractFrom(patchSetAttribute)) + .andReturn(Sets.newHashSet(propertyPatchSet)); + + event.reason = "testReason"; + Property propertyReason = createMock(Property.class); + expect(propertyFactory.create("reason", "testReason")) + .andReturn(propertyReason); + + changeAttribute.project = "testProject"; + patchSetAttribute.revision = "testRevision"; + + Set<Property> common = Sets.newHashSet(); + common.add(propertyChange); + common.add(propertySubmitter); + common.add(propertyPatchSet); + common.add(propertyReason); + + eventHelper(event, "ChangeRestoredEvent", "change-restored", common); + } + + public void testCommentAddedEvent() { + CommentAddedEvent event = new CommentAddedEvent(); + + ChangeAttribute changeAttribute = createMock(ChangeAttribute.class); + event.change = changeAttribute; + Property propertyChange = createMock(Property.class); + expect(propertyAttributeExtractor.extractFrom(changeAttribute)) + .andReturn(Sets.newHashSet(propertyChange)); + + AccountAttribute accountAttribute = createMock(AccountAttribute.class); + event.author = accountAttribute; + Property propertySubmitter = createMock(Property.class); + expect(propertyAttributeExtractor.extractFrom(accountAttribute, + "commenter")).andReturn(Sets.newHashSet(propertySubmitter)); + + PatchSetAttribute patchSetAttribute = createMock(PatchSetAttribute.class); + event.patchSet = patchSetAttribute; + Property propertyPatchSet = createMock(Property.class); + expect(propertyAttributeExtractor.extractFrom(patchSetAttribute)) + .andReturn(Sets.newHashSet(propertyPatchSet)); + + event.comment = "testComment"; + Property propertyComment = createMock(Property.class); + expect(propertyFactory.create("comment", "testComment")) + .andReturn(propertyComment); + + changeAttribute.project = "testProject"; + patchSetAttribute.revision = "testRevision"; + + Set<Property> common = Sets.newHashSet(); + common.add(propertyChange); + common.add(propertySubmitter); + common.add(propertyPatchSet); + common.add(propertyComment); + + eventHelper(event, "CommentAddedEvent", "comment-added", common); + } + + public void testPatchSetCreatedEvent() { + PatchSetCreatedEvent event = new PatchSetCreatedEvent(); + + ChangeAttribute changeAttribute = createMock(ChangeAttribute.class); + event.change = changeAttribute; + Property propertyChange = createMock(Property.class); + expect(propertyAttributeExtractor.extractFrom(changeAttribute)) + .andReturn(Sets.newHashSet(propertyChange)); + + AccountAttribute accountAttribute = createMock(AccountAttribute.class); + event.uploader = accountAttribute; + Property propertySubmitter = createMock(Property.class); + expect(propertyAttributeExtractor.extractFrom(accountAttribute, + "uploader")).andReturn(Sets.newHashSet(propertySubmitter)); + + PatchSetAttribute patchSetAttribute = createMock(PatchSetAttribute.class); + event.patchSet = patchSetAttribute; + Property propertyPatchSet = createMock(Property.class); + expect(propertyAttributeExtractor.extractFrom(patchSetAttribute)) + .andReturn(Sets.newHashSet(propertyPatchSet)); + + changeAttribute.project = "testProject"; + patchSetAttribute.revision = "testRevision"; + + Set<Property> common = Sets.newHashSet(); + common.add(propertyChange); + common.add(propertySubmitter); + common.add(propertyPatchSet); + + eventHelper(event, "PatchSetCreatedEvent", "patchset-created", common); + } + + public void testRefUpdatedEvent() { + RefUpdatedEvent event = new RefUpdatedEvent(); + + AccountAttribute accountAttribute = createMock(AccountAttribute.class); + event.submitter = accountAttribute; + Property propertySubmitter = createMock(Property.class); + expect(propertyAttributeExtractor.extractFrom(accountAttribute, + "submitter")).andReturn(Sets.newHashSet(propertySubmitter)); + + RefUpdateAttribute refUpdateAttribute = + createMock(RefUpdateAttribute.class); + event.refUpdate = refUpdateAttribute; + Property propertyRefUpdated = createMock(Property.class); + expect(propertyAttributeExtractor.extractFrom(refUpdateAttribute)) + .andReturn(Sets.newHashSet(propertyRefUpdated)); + + refUpdateAttribute.project = "testProject"; + refUpdateAttribute.newRev = "testRevision"; + + Set<Property> common = Sets.newHashSet(); + common.add(propertySubmitter); + common.add(propertyRefUpdated); + + eventHelper(event, "RefUpdatedEvent", "ref-updated", common); + } + + private void eventHelper(ChangeEvent event, String className, String type, + Set<Property> common) { + PropertyExtractor propertyExtractor = injector.getInstance( + PropertyExtractor.class); + + Property propertyEvent = createMock(Property.class); + expect(propertyFactory.create("event", "com.google.gerrit.server.events." + + className)).andReturn(propertyEvent); + + Property propertyEventType = createMock(Property.class); + expect(propertyFactory.create("event-type", type)) + .andReturn(propertyEventType); + + Property propertyAssociationFooter = createMock(Property.class); + expect(propertyFactory.create("association", "footer")) + .andReturn(propertyAssociationFooter); + + Property propertyAssociationAnywhere = createMock(Property.class); + expect(propertyFactory.create("association", "anywhere")) + .andReturn(propertyAssociationAnywhere).times(2); + + Property propertyAssociationBody = createMock(Property.class); + expect(propertyFactory.create("association", "body")) + .andReturn(propertyAssociationBody); + + Property propertyIssue42 = createMock(Property.class); + expect(propertyFactory.create("issue", "42")) + .andReturn(propertyIssue42); + + Property propertyIssue4711 = createMock(Property.class); + expect(propertyFactory.create("issue", "4711")) + .andReturn(propertyIssue4711); + + HashMap<String,Set<String>> issueMap = Maps.newHashMap(); + issueMap.put("4711", Sets.newHashSet("body", "anywhere")); + issueMap.put("42", Sets.newHashSet("footer", "anywhere")); + expect(issueExtractor.getIssueIds("testProject", "testRevision")) + .andReturn(issueMap); + + replayMocks(); + + Set<Set<Property>> actual = propertyExtractor.extractFrom(event); + + Set<Set<Property>> expected = Sets.newHashSet(); + Set<Property> properties = Sets.newHashSet(); + properties.add(propertyEvent); + properties.add(propertyEventType); + properties.add(propertyAssociationAnywhere); + properties.add(propertyAssociationFooter); + properties.add(propertyIssue42); + properties.addAll(common); + expected.add(properties); + + properties = Sets.newHashSet(); + properties.add(propertyEvent); + properties.add(propertyEventType); + properties.add(propertyAssociationAnywhere); + properties.add(propertyAssociationBody); + properties.add(propertyIssue4711); + properties.addAll(common); + expected.add(properties); + assertEquals("Properties do not match", expected, actual); + } + + public void setUp() throws Exception { + super.setUp(); + injector = Guice.createInjector(new TestModule()); + } + + private class TestModule extends FactoryModule { + @Override + protected void configure() { + issueExtractor = createMock(IssueExtractor.class); + bind(IssueExtractor.class).toInstance(issueExtractor); + + propertyAttributeExtractor = createMock(PropertyAttributeExtractor.class); + bind(PropertyAttributeExtractor.class).toInstance( + propertyAttributeExtractor); + + propertyFactory = createMock(Property.Factory.class); + bind(Property.Factory.class).toInstance(propertyFactory); + //factory(Property.Factory.class); + } + } + + private class DummyChangeEvent extends ChangeEvent { + } +} \ No newline at end of file