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